1. 程式人生 > >二叉樹的應用

二叉樹的應用

一、層序遍歷的應用:

映象:還需要引入佇列,同上一篇部落格。

.h

# pragma once
# include<assert.h>
# include<malloc.h>
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include"Queue.h"
typedef char BTDataType;
typedef struct BinTreeBTNode
{
	struct BinTreeBTNode* _pLeft;
	struct BinTreeBTNode* _pRight;
	BTDataType _data;
}BTBTNode,*PBTNode;

PBTNode BuyBinTreeBTNode(BTDataType data);
 
void _CreateBinTree(PBTNode* pRoot, BTDataType array[], int size, int* index, BTDataType invalid);
 
void CreateBinTree(PBTNode* pRoot, BTDataType array[], int size, BTDataType invalid);
 
//拷貝一棵樹,根加左子樹加右子樹
PBTNode CopyBinTree(PBTNode pRoot);
 
//二叉樹的前需遍歷:根+左子樹+右子樹
void PreOrder(PBTNode pRoot);
 
//中序遍歷:左子樹+根節點+右子樹
void InOrder(PBTNode pRoot);
 
//後序遍歷:左子樹+右子樹+根節點
void PostOrder(PBTNode pRoot);
 
void DestroyBinTree(PBTNode* pRoot);

void MirrorBinTree(PBTNode pRoot);
void MirrorBinTreeNor(PBTNode pRoot);

.c

# include"BinaryTree.h"

 
//#define NULL 0
PBTNode BuyBinTreeNode(DataType data)
{
	PBTNode pNewNode = (PBTNode)malloc(sizeof(Node));
	if (NULL == pNewNode)
	{
		assert(0);
		return NULL;
	}
	pNewNode->_data = data;
	pNewNode->_pLeft = NULL;
	pNewNode->_pRight = NULL;
	return pNewNode;
}
void _CreateBinTree(PBTNode* pRoot, DataType array[], int size, int* index, DataType invalid)
{
	assert(pRoot);//此時pRoot代表外部實參的地址,可以改變指向
	assert(index);
	if (*index < size&&invalid != array[*index]){
		*pRoot = BuyBinTreeNode(array[*index]);
		//建立根節點的左子樹
		++(*index);
		_CreateBinTree(&(*pRoot)->_pLeft, array, size, index, invalid);
		//建立根節點的右子樹
		++(*index);
		_CreateBinTree(&(*pRoot)->_pRight, array, size, index, invalid);
	}
}
void CreateBinTree(PBTNode* pRoot, DataType array[], int size, DataType invalid)
{
	int index = 0;
	_CreateBinTree(pRoot, array, size, &index, invalid);

}
//拷貝一棵樹,根加左子樹加右子樹
PBTNode CopyBinTree(PBTNode pRoot){
	PBTNode pNewRoot = NULL;
	if (pRoot){
		//拷貝根節點
		pNewRoot = BuyBinTreeNode(pRoot->_data);
		//拷貝根節點的左子樹
		if (pRoot->_pLeft)
			pNewRoot->_pLeft = CopyBinTree(pRoot->_pLeft);
		//拷貝根節點的右子樹
		if (pRoot->_pRight)
			pNewRoot->_pRight = CopyBinTree(pRoot->_pRight);
	}
	return pNewRoot;
}
//二叉樹的前需遍歷:根+左子樹+右子樹
void PreOrder(PBTNode pRoot)
{
	if (pRoot)
	{
		printf("%c ", pRoot->_data);
		PreOrder(pRoot->_pLeft);
		PreOrder(pRoot->_pRight);
	}
}
//中序遍歷:左子樹+根節點+右子樹
void InOrder(PBTNode pRoot)
{
	if (pRoot)
	{

		InOrder(pRoot->_pLeft);
		printf("%c ", pRoot->_data);
		InOrder(pRoot->_pRight);
	}
}
//後序遍歷:左子樹+右子樹+根節點
void PostOrder(PBTNode pRoot)
{
	if (pRoot)
	{

		PostOrder(pRoot->_pLeft);
		PostOrder(pRoot->_pRight);
		printf("%c ", pRoot->_data);
	}
}
void LevelOrder(PBTNode pRoot)
{
	Queue q;
	if (NULL == pRoot)
		return;
	QueueInit(&q);//初始化根節點
	//把根節點的地址加到樹裡面
	QueuePush(&q, pRoot);
	while (!QueueEmpty(&q)){
		//遍歷
		PBTNode pCur = QueueFront(&q);
		printf("%c  ", pCur->_data);
		//QueuePop(&q);出佇列的操作也可以放在這個位置上
		//把元素放到佇列裡
		if (pCur->_pLeft)
			QueuePush(&q, pCur->_pLeft);
		if (pCur->_pRight)
			QueuePush(&q, pCur->_pRight);
		//從佇列裡面拿出去
		QueuePop(&q);
	}
}
void DestroyBinTree(PBTNode* pRoot)
{
	assert(pRoot);
	if (*pRoot){
		//銷燬左子樹
		DestroyBinTree(&(*pRoot)->_pLeft);
		//銷燬右子樹
		DestroyBinTree(&(*pRoot)->_pRight);
		//銷燬根節點
		free(*pRoot);
		*pRoot = NULL;
	}
}

void Swap(PBTNode* pLeft, PBTNode* pRight)
{
	PBTNode tmp = *pLeft;
	*pLeft = *pRight;
	*pRight = tmp;
}
//非遞迴實現
void MirrorBinTreeNor(PBTNode pRoot){
	Queue q;
	if (NULL == pRoot)
		return;
	QueueInit(&q);
	QueuePush(&q, pRoot);
	while (!QueueEmpty(&q))
	{
		//如果當前佇列不為空,取對頭元素
		PBTNode pCur = QueueFront(&q);
		//交換左右孩子
		Swap(&(pCur->_pLeft),&(pCur->_pRight));
		if (pCur->_pLeft)
			QueuePush(&q, pCur->_pLeft);//將左孩子寫入
		if (pCur->_pRight)
			QueuePush(&q, pCur->_pRight);
	}
}
//遞迴實現映象
void MirrorBinTree(PBTNode pRoot)
{
	if (pRoot)
	{
		Swap(&(pRoot->_pLeft), &(pRoot->_pRight));
		MirrorBinTree(pRoot->_pLeft);
		MirrorBinTree(pRoot->_pRight);
	}
}
void TestBinTree()
{
	char* str = "ABD###CE##F";
	PBTNode pRoot = NULL, pNewRoot;
	CreateBinTree(&pRoot, str, strlen(str), '#');
	pNewRoot = CopyBinTree(pRoot);

	printf("前序遍歷:");
	PreOrder(pRoot);
	printf("\n");

	printf("中序遍歷:");
	InOrder(pRoot);
	printf("\n");

	printf("後序遍歷:");
	PostOrder(pRoot);
	printf("\n");

	printf("層序遍歷:");
	LevelOrder(pRoot);

	MirrorBinTree(pRoot);
	MirrorBinTreeNor(pRoot);
	printf("層序遍歷:");
	LevelOrder(pRoot);
}

//A B D # # # C E # 


 

二、

1、求二叉樹中結點總的個數;

遞迴呼叫的時間複雜度:遞迴呼叫總的次數*每次遞迴呼叫的次數,一個結點兩個指標域,n個結點則有2*n個指標域;每個指標域都是一次函式呼叫,遞迴程式總的呼叫次數為2n,每一次呼叫了兩次,則為4n。所以節點總的個數為O(n)。

int BinTreeSize(PBTNode pRoot)
{
	if (NULL == pRoot)
		return 0;
	int left = BinTreeSize(pRoot->_pLeft);
	int right = BinTreeSize(pRoot->_pRight);
	return left + right + 1;
}

測試的程式碼:

void TestBinTree()
{
	char* str = "ABD###CE##F";
	PBTNode pRoot = NULL, pNewRoot;
	CreateBinTree(&pRoot, str, strlen(str), '#');
	pNewRoot = CopyBinTree(pRoot);

	printf("前序遍歷:");
	PreOrder(pRoot);
	printf("\n");

	printf("中序遍歷:");
	InOrder(pRoot);
	printf("\n");

	printf("後序遍歷:");
	PostOrder(pRoot);
	printf("\n");

	printf("層序遍歷:");
	LevelOrder(pRoot);

	MirrorBinTree(pRoot);
	MirrorBinTreeNor(pRoot);
	printf("層序遍歷:");
	LevelOrder(pRoot);
	printf("\n");

	printf("二叉樹中結點的個數為:%d\n", BinTreeSize(pRoot));
}

2、二叉樹中葉子節點的總的個數

葉子節點:沒有孩子的節點,度為0的節點

int BinTreeLeaf(PBTNode pRoot)
{
	if (pRoot == NULL)
		return 0;
	if (NULL == pRoot->_pLeft&&NULL == pRoot->_pRight)
		//左孩子和右孩子都為空,則只有一個葉子節點
		return 1;

	return BinTreeLeaf(pRoot->_pLeft) + BinTreeLeaf(pRoot->_pRight);
}

測試程式碼:

	printf("二叉樹中葉子結點的個數為:%d\n", BinTreeLeaf(pRoot));

3、判斷一個節點是否在一棵二叉樹中

struct BinaryTree
{
    BinaryTree(char data)
    :_pLeft(NULL)
    , _pRight(NULL)
    , _data(data)
    {}
    BinaryTree *_pLeft;
    BinaryTree *_pRight;
    char _data;
};
//建立二叉樹
void CreateBinaryTree(BinaryTree *&pRoot, char *str,size_t size, size_t &index)
{
    if (index < size && str[index] != '#')
    {
        pRoot = new BinaryTree(str[index]);
        CreateBinaryTree(pRoot->_pLeft, str, size, ++index);
        CreateBinaryTree(pRoot->_pRight, str, size, ++index);
    }
}
//遞迴實現
bool IsNodeInTree(BinaryTree *pRoot,BinaryTree *pNode)
{
    if (NULL == pRoot || NULL == pNode)
        return false;
    if (pRoot->_data == pNode->_data)
        return true;
    if (IsNodeInTree(pRoot->_pLeft, pNode) || IsNodeInTree(pRoot->_pRight, pNode))
        return true;

        return false;
}

4、獲取一個節點的雙親節點

 

5、獲取一個節點的左孩子節點

 

6、獲取一個節點的右孩子節點

 

7、判斷一棵二叉樹是否為完全二叉樹(層序遍歷變形)

1>如果樹為空,則直接返回錯
2>如果樹不為空:層序遍歷二叉樹
2.1>如果一個結點左右孩子都不為空,則pop該節點,將其左右孩子入佇列;
2.1>如果遇到一個結點,左孩子為空,右孩子不為空,則該樹一定不是完全二叉樹;
2.2>如果遇到一個結點,左孩子不為空,右孩子為空;或者左右孩子都為空;則該節點之後的佇列中的結點都為葉子節點;該樹才是完全二叉樹,否則就不是完全二叉樹;

int IsCompleteBinTree(pNode pRoot)
{
	Queue q;
	int flag=0;
	if (NULL==pRoot)
		return 1;



	QueueInit(&q);
	QueuePush(&q,pRoot);


	while (!QueueEmpty(&q))
	{
		pNode pCur=QueueFront(&q);
		if (flag)
		{
			if (pCur->_pLeft||pCur->_pRight)
				return 0;

		}

		else
		{
			if (pCur ->_pLeft&&pCur->_pRight)
			{
				QueuePush(&q,pRoot->_pLeft);
				QueuePush(&q,pRoot->_pRight);
			}
			else if (pCur->_pRight)
				return 0;
			else if(pCur->_pLeft) {
				QueuePush(&q,pRoot->_pLeft);
				flag=1;
			}
			else 
				flag=1;
			QueuePop(&q);
		}
	}
	return 1;
}
bool IsCompleteTree(BinaryTreeNode *pRoot)
{
         if(pRoot == NULL)
               return false;

          queue<BinaryTreeNode*> q;
          q.push(pRoot);
          BinaryTreeNode* pCur = q.front();
          while(pCur != NULL)
          {
               q.pop();
               q.push(pCur -> left);
               q.push(pCur -> right);
               pCur = q.front();
          }

          q.pop();//把空pop出來
          //因為以經有一個空了,所以只要頭不為空就不是完全二叉樹
          while(! q.empty())
          {
               if(q.front() != NULL)
                    return false;
               q.pop();
          }
          return true;
}