《劍指offer》:[39-1]判斷是否為平衡二叉樹

塵虛緣_KY發表於2016-06-19
題目:輸入一棵二叉樹的結點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意結點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。
上圖中的二叉樹就是一棵平衡二叉樹。
分析:有了求二叉樹深度的思路後,我們很快就能找到求解該問題的方法,就是從根結點開始開始判斷其左右子結點的深度之差是否為1。如果從根結點開始到葉子結點的每一個結點的左右子樹的深度相差都不超過1,則說明該二叉樹是平衡二叉樹。但是其時間複雜度接近O(N*N),因為裡面有重複的遍歷和訪問。例如我們在判斷8這個根結點是否是平衡的時候,我們需要判斷其左右的兩棵子樹深度的差,需遍歷3,5,7,6,但是當我們判斷5結點是不是平衡的時候,我們還得遍歷3,7,6這三個節點,所以重複的遍歷使效率十分低下。還記得面試12(書上是面試9)中的斐波拉切數列的求法嗎?典型的遞迴,但是那裡的遞迴效率不高,和此題有相同的問題。
具體實現程式碼如下:
#include <iostream>
using namespace std;
struct BinaryTree
{
	int data;
	BinaryTree *pLeft;
	BinaryTree *pRight;
};
BinaryTree *pRoot1=NULL;
int arr[7]={8,5,15,3,7,16,6};
void InserTree(BinaryTree **root,int data)
{
	BinaryTree *temp=new BinaryTree;
	temp->data=data;
	temp->pLeft=temp->pRight=NULL;
	if(NULL==*root)
	{
		*root=temp;
	}
	else
	{
		BinaryTree *current=*root;
		BinaryTree *back=NULL;
		while(current)
		{
			back=current;
			if(data > current->data)
				current=current->pRight;
			else
				current=current->pLeft;
		}
		if(NULL==back->pLeft)
			back->pLeft=temp;
		else
			back->pRight=temp;
	}
}
void CreateTreeLoop(BinaryTree **root,int *array,int length)
{
	for(int i=0;i<length;i++)
		InserTree(root,array[i]);
}
void Inorder(BinaryTree *root)
{
	if(NULL!=root)
	{
		Inorder(root->pLeft);
		cout<<root->data<<" ";
		Inorder(root->pRight);
	}
}
int TreeDepth(BinaryTree*root)
{
	if(NULL==root)
		return 0;
	int left=TreeDepth(root->pLeft);
	int right=TreeDepth(root->pRight);
	return left>right?(left+1):(right+1);
}
bool IsBalance(BinaryTree *root)
{
	if(NULL==root)
		return true;
	int leftIsBla=TreeDepth(root->pLeft);
	int rightIsBla=TreeDepth(root->pRight);
	int diff=leftIsBla-rightIsBla;
	if(diff>1 || diff<-1  )
		return false;
	return IsBalance(root->pLeft) && IsBalance(root->pRight);
}


int main()
{
	CreateTreeLoop(&pRoot1,arr,7);
	cout<<"中序遍歷:";
	Inorder(pRoot1);
	cout<<endl;
	bool result=IsBalanced(pRoot1);
	if(result)
		cout<<"The tree is balance!"<<endl;
	else
		cout<<"The tree is not a balance tree!"<<endl;
	system("pause");
	return 0;
}

執行結果:


   基於上面重複遍歷效率較低的問題,我們對其進行了改進,通過後續遍歷,從葉子結點->到根結點開始判斷該樹是不是平衡的。因為當我們在遍歷某節點的左右子節點的左右子節點是否平衡後,我們相應的就得到了當前節點的深度,我們就不用重複遍歷該樹的一些節點,當最後遍歷到樹的根結點的時候,也就判斷了整棵二叉樹是不是平衡二叉樹。
其是實現關鍵程式碼如下:
bool IsBalanceHelp(BinaryTree *root,int *depth)
{
	if(root==NULL)
	{
		*depth=0;
		return true;
	}
	int left,right;
	if(IsBalanceHelp(root->pLeft,&left)&& IsBalanceHelp(root->pRight,&right))
	{
		int diff=left-right;
		if(diff<=1 && diff>=-1)
		{
			*depth=1+(left>right?left:right); //當遍歷每個結點時,記錄下該結點的深度,下次就不用再遍歷已經遍歷過的結點;
			return true;
		}
	}
	return false;
}
bool IsBalanced(BinaryTree *root)
{
	int depth=0;
	return IsBalanceHelp(root,&depth);
}
次種演算法避免了不必要的重複計算,對於資料量大的二叉樹效率明顯提高。





相關文章