程序员面试金典: 9.4树与图 4.1实现一个函数检查二叉树是否平衡——O(N)时间解法

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string>

using namespace std;

/*
问题:实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两颗子树的高度差不超过1.
分析:关于树的大部分问题都是和递归相关。
      所以如果一棵树的左子树的高度和右子树各自平衡,且这两颗子树的高度之差不超过1即可。
	  递归基:
	  isAVLTree(Tree* head)
	  {
	     //如果还树为空,一定是平衡的
		 if(NULL == head)
		 {
		   return true
		 }
	  }

	  这里的关键是需要记录树的高度,最好能做成根据节点就能知道高度

输入: 
输入可能包含多个测试样例,输入以EOF结束。 
对于每个测试案例,输入的第一行一个整数n(1<=n<=1000, :n代表将要输入的二叉树元素的个数(节点从1开始编号)。接下来一行有n个数字,代表第i个二叉树节点的元素的值。接下来有n行,每行有一个字母Ci。 
Ci=’d’表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号。 
Ci=’l’表示第i个节点有一个左孩子,紧接着是左孩子的编号。 
Ci=’r’表示第i个节点有一个右孩子,紧接着是右孩子的编号。 
Ci=’z’表示第i个节点没有子孩子。 
输出: 

样例输入:
6
8 6 5 7 10 9
d 2 5 
d 3 4 
z 
z 
l 6 
z 


9 
8 6 5 7 10 9 11 13 15
d 2 5 
d 3 4 
z 
z 
d 6 7 
l 8
z 
r 9
z

样例输出:
Is AVL Tree!
Not AVL Tree!



关键:
1 判断平衡二叉树,可以用: 在判断AVL树的过程中计算左右子树的高度,时间复杂度为O(NlogN)
2  考虑到高度可以用于计算高度,也可以用于判断左右子树是否平衡,
  当左右子树高度差>1,此时返回-1表示不平衡;否则返回: 左右子树高度中的较大值+1 作为当前节点的高度
int checkHeight(TreeNode* pHead)
{
	if(NULL == pHead)
	{
		return 0;
	}
	//获取左子树高度
	int leftHeight = checkHeight(pHead->_pLeft);
	if(leftHeight == -1)
	{
		return -1;
	}

	//获取右子树高度
	int rightHeight = checkHeight(pHead->_pRight);
	if(rightHeight == -1)
	{
		return -1;
	}

	//如果左右子树都分别平衡,那么计算当前节点是否平衡
	int heightDiff = abs(rightHeight - leftHeight);
	if(heightDiff > 1)
	{
		return -1;
	}
	//如果树是平衡的,返回该树的高度 = 左右子树高度的较大值 + 1
	else
	{
		return max(leftHeight , rightHeight) + 1;
	}
}
牛逼

*/

typedef struct TreeNode
{
	TreeNode():_value(-1),_pLeft(NULL),_pRight(NULL),_pParent(NULL){}
	int _value;
	//树中肯定包含左子树和右子树,还包括当前节点自身的值
	TreeNode* _pLeft;
	TreeNode* _pRight;
	TreeNode* _pParent; // 父节点,根节点的父节点为空,高度
	int _index; //创建的节点的下标
}TreeNode;

//关键就设置一个节点数组
const int MAXSIZE = 1001;
TreeNode g_treeNodeArray[MAXSIZE];
int g_index; //用于标示创建的节点的下标

//创建节点
TreeNode* createNode()
{
	//先使节点标记累加,初始化节点中左右孩子的值为NULL
	++g_index;
	g_treeNodeArray[g_index]._pLeft = g_treeNodeArray[g_index]._pRight = g_treeNodeArray[g_index]._pParent = NULL;
	return &g_treeNodeArray[g_index];
}

//获取树的顶点
TreeNode* getTreeHeadNode(TreeNode* pNode)
{
	//如果当前传入的节点为空,就直接返回该树的顶点为空
	if(NULL == pNode)
	{
		return NULL;
	}

	//根据树的顶点没有父节点,因此如果某个节点的父节点为空,该节点就是树的顶点
	if(NULL == pNode->_pParent)
	{
		return pNode;
	}
	return getTreeHeadNode(pNode->_pParent);
}

int max(int a, int b)
{
	return a > b ? a : b;
}

//该函数的作用是:如果pHead为树的顶点的树是平衡的,则返回以pHead为顶点的树的高度;否则,返回-1表示已pHead为顶点的树是不平衡的
int checkHeight(TreeNode* pHead)
{
	if(NULL == pHead)
	{
		return 0;
	}
	//获取左子树高度
	int leftHeight = checkHeight(pHead->_pLeft);
	if(leftHeight == -1)
	{
		return -1;
	}

	//获取右子树高度
	int rightHeight = checkHeight(pHead->_pRight);
	if(rightHeight == -1)
	{
		return -1;
	}

	//如果左右子树都分别平衡,那么计算当前节点是否平衡
	int heightDiff = abs(rightHeight - leftHeight);
	if(heightDiff > 1)
	{
		return -1;
	}
	//如果树是平衡的,返回该树的高度 = 左右子树高度的较大值 + 1
	else
	{
		return max(leftHeight , rightHeight) + 1;
	}
}

bool isAVLTree(TreeNode* head)
{
	int height = checkHeight(head);
	if(height == -1)
	{
		return false;
	}
	else
	{
		return true;
	}
}

int main(int argc, char* argv[])
{
	int nodeNum;
	int value;
	string childFlag;
	int leftChild;
	int rightChild;
	while(cin >> nodeNum)
	{
		g_index = 0;

		//输入n个树节点对应的值,实际上就是创建节点
		for(int i = 0 ; i < nodeNum ; i++)
		{
			cin >> value;
			TreeNode* pNode = createNode();
			pNode->_value = value;
		}

		//接下来就是对n个节点的孩子节点进行赋值
		for(int i = 1 ; i <= nodeNum ; i++)
		{
			cin >> childFlag;
			if("d" == childFlag)
			{
				cin >> leftChild >> rightChild;
				g_treeNodeArray[i]._pLeft = &g_treeNodeArray[leftChild];
				g_treeNodeArray[i]._pRight = &g_treeNodeArray[rightChild];

				//注意设置父节点的指向,否则无法从任意节点推算根节点
				g_treeNodeArray[leftChild]._pParent = &g_treeNodeArray[i];
				g_treeNodeArray[rightChild]._pParent = &g_treeNodeArray[i];
			}
			else if("l" == childFlag)
			{
				cin >> leftChild;
				g_treeNodeArray[i]._pLeft = &g_treeNodeArray[leftChild];
				g_treeNodeArray[leftChild]._pParent = &g_treeNodeArray[i];
			}
			else if("r" == childFlag)
			{
				cin >> rightChild;
				g_treeNodeArray[i]._pRight = &g_treeNodeArray[rightChild];
				g_treeNodeArray[rightChild]._pParent = &g_treeNodeArray[i];
			}
			//没有孩子节点无需处理
			else if("z" == childFlag)
			{

			}
			else
			{
				cout << "command is error!" << endl;
			}
		}

		//获取树的顶点
		TreeNode* pHead = getTreeHeadNode( &g_treeNodeArray[1] );

		//高度验证正确后,判断平衡树就可以了
		bool isAVL = isAVLTree(pHead);
		if(isAVL)
		{
			cout << "Is AVL Tree!" << endl;
		}
		else
		{
			cout << "Not AVL Tree!" << endl;
		}
	}
	getchar();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值