程序员面试题精选-- 判断二叉树是不是平衡的

转自何海涛日志http://zhedahht.blog.163.com/

题目:输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。例如下图中的二叉树就是一棵平衡二叉树:

我们很容易就能想到一个思路:在遍历树的每个结点的时候,调用函数TreeDepth得到它的左右子树的深度。如果每个结点的左右子树的深度相差都不超过1,按照定义它就是一棵平衡的二叉树。

参考代码如下:

//判断二叉树是否为平衡二叉树,该算法特点为简单明了,但会出现结点被重复遍历,效率稍低 
bool IsBalanced(BinaryTreeNode *root)
{
	if(root==NULL)
		return true;
	else
	{
		int left = TreeDepth(root->lchild);
		int right = TreeDepth(root->rchild);
		int dif = left - right;
		if(dif>1 || dif<-1)
			return false;
		
		return IsBalanced(root->lchild) && IsBalanced(root->rchild);
	}
} 

int TreeDepth(BinaryTreeNode *root)
{
	if(root==NULL)
		return 0;
	else
	{
		int left_depth = TreeDepth(root->lchild);
		int right_depth = TreeDepth(root->rchild);
		return 1 + (left_depth > right_depth ? left_depth : right_depth);
	}
}

上面的代码固然简洁,但我们也要注意到由于一个节点会被重复遍历多次,这种思路的时间效率不高。例如在函数IsBalance中输入上图中的二叉树,首先判断根结点(值为1的结点)的左右子树是不是平衡结点。此时我们将往函数TreeDepth输入左子树根结点(值为2的结点),需要遍历结点457。接下来判断以值为2的结点为根结点的子树是不是平衡树的时候,仍然会遍历结点457。毫无疑问,重复遍历同一个结点会影响性能。接下来我们寻找不需要重复遍历的算法。

如果我们用后序遍历的方式遍历二叉树的每一个结点,在遍历到一个结点之前我们已经遍历了它的左右子树。只要在遍历每个结点的时候记录它的深度(某一结点的深度等于它到叶节点的路径的长度),我们就可以一边遍历一边判断每个结点是不是平衡的。下面是这种思路的参考代码:

//更为高效的算法,后序遍历二叉树,遍历每个结点时记录它的深度
bool IsBalanced(BinaryTreeNode *root, int &depth)
{
	if(root==NULL)
	{
		depth = 0;
		return true;
	}
	
	int left,right;
	if(IsBalanced(root->lchild, left) && IsBalanced(root->rchild, right))
	{
		int dif = left - right;
		if(dif<=1 && dif>=-1)
		{
			depth = 1 + (left > right ? left : right);
			return true;
		}
	} 
	
	return false;
}

在上面的代码中,我们用后序遍历的方式遍历整棵二叉树。在遍历某结点的左右子结点之后,我们可以根据它的左右子结点的深度判断它是不是平衡的,并得到当前结点的深度。当最后遍历到树的根结点的时候,也就判断了整棵二叉树是不是平衡二叉树了。



你可能感兴趣的:(程序员面试题)