程序员面试金典: 9.4树与图 4.1实现一个函数检查二叉树是否平衡。
2016-12-24 17:27
369 查看
#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 构建树的节点,采用的是直接静态创建N个节点,每次创建节点,就是把静态节点数组中某个节点地址分配给它 对于某个节点的子节点,则直接根据子节点下标,取出静态节点数组中对应节点地址 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]; } 2 判断平衡树中需要计算左右子树的高度,注意不是左右孩子节点的高度 int getTreeHeight(TreeNode* pNode) { if(NULL == pNode) { return 0; } int leftHeight = getTreeHeight(pNode->_pLeft) + 1; int rightHeight = getTreeHeight(pNode->_pRight) + 1; int height = leftHeight > rightHeight ? leftHeight : rightHeight; return height; } 3判断平衡树除了递归基放在前面,判定条件放在中间,而对左右子树判断是否平衡要放在最后,这是因为,如果把判断左右子树 平衡放在中间,那么判定条件在最后面起不到作用 int leftHeight= getTreeHeight(head->_pLeft); int rightHeight = getTreeHeight(head->_pRight); int result = abs(leftHeight - rightHeight); if(result > 1) { return false; } //返回两个子树是否平衡 else { return isAVLTree(head->_pLeft) && isAVLTree(head->_pRight); } */ typedef struct TreeNode { TreeNode():_value(-1),_height(-1),_pLeft(NULL),_pRight(NULL),_pParent(NULL){} int _value; int _height; //该节点距离树顶部的高度,第一层高度为1,默认初始化树的根节点高度为1 //树中肯定包含左子树和右子树,还包括当前节点自身的值 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]; } //获取当前节点高度,仍然是用递归做 int getHeight(TreeNode* pNode) { //如果当前节点为空,高度为0? ,这个有问题,应该修改为如果当前节点为空,其高度等于其父节点高度 //参见这种情况:一个父节点只有左孩子,父节点高度为h,左孩子高度则为h+1,如果把父节点的右孩子(实际为空)的高度设置为0,会有可能判断得出为非平衡树 //此时应该设置空节点高度为其父节点高度,但不对,当前节点都为空了,怎么可能获取到父节点,只能在调用的地方控制,做非空检查,如果为空,就用其父节点计算其高度 if(NULL == pNode) { return 0; } //记忆化搜索 if(pNode->_height != -1) { return pNode->_height; } //如果是遇到根节点,那么根节点对应高度为0 else if(pNode->_pParent == NULL) { return 0; } else { return getHeight(pNode->_pParent) + 1; } } //获取树的顶点 TreeNode* getTreeHeadNode(TreeNode* pNode) { //如果当前传入的节点为空,就直接返回该树的顶点为空 if(NULL == pNode) { return NULL; } //根据树的顶点没有父节点,因此如果某个节点的父节点为空,该节点就是树的顶点 if(NULL == pNode->_pParent) { return pNode; } return getTreeHeadNode(pNode->_pParent); } //其实是计算左子树高度和右子树高度,而不是左孩子和右孩子高度;这个函数作用是计算以pNode为顶点的树的高度(左右子树中的较大值) int getTreeHeight(TreeNode* pNode) { if(NULL == pNode) { return 0; } int leftHeight = getTreeHeight(pNode->_pLeft) + 1; int rightHeight = getTreeHeight(pNode->_pRight) + 1; int height = leftHeight > rightHeight ? leftHeight : rightHeight; return height; } bool isAVLTree(TreeNode* head) { //如果还树为空,一定是平衡的 if(NULL == head) { return true; } //如果左子树和右子树都不空,那么需要判断两者的高度之差是否<=1,并且两颗子树都需要平衡,必须要记录高度 else { int leftHeight= getTreeHeight(head->_pLeft); int rightHeight = getTreeHeight(head->_pRight); int result = abs(leftHeight - rightHeight); if(result > 1) { return false; } //返回两个子树是否平衡 else { return isAVLTree(head->_pLeft) && isAVLTree(head->_pRight); } } } 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; }
相关文章推荐
- 程序员面试金典: 9.4树与图 4.1实现一个函数检查二叉树是否平衡——O(N)时间解法
- 程序员面试金典: 9.4树与图 4.5实现一个函数,检查一颗二叉树是否为二叉查找树
- 实现一个函数,检查二叉树是否平衡。
- 检查一个二叉树是否平衡的算法分析与C++实现
- 检查一个二叉树是否平衡的算法分析与C++实现
- (015)实现一个函数检查一棵树是否平衡(keep it up)
- (015)实现一个函数来检查是否平衡树(keep it up)
- 实现一颗二叉树,检查二叉树是否平衡(java实现)
- 实现一个函数,判断输入字符串是否对称?
- [函数]function CheckUrl(url: string): Boolean; //检查一个URL是否有效函数
- 用最简单的函数实现功能:判断一个int数据是否是2的x次幂(不能使用循环)。
- 算法--写一个函数检查字符是否是整数,如果是返回其整数值
- 能实现检查窗口是否存在的函数
- ORACLE:检查一个表(TABLE)/函数(FUNCTION)/过程(PROCEDRE)是否存在
- javascript 如何判断元素是否包含一个特定的类,hasClass函数的实现
- 任意输入20个正整数,找出其中的素数,并将这些素数按由小到大排序。要求:判断一个数是否为素数用函数实现:排序用函数实现
- 写一个函数,检查字符是否是整数,如果是,返回其整数值
- 写一个函数,检查字符是否是整数,如果是,返回其整数值
- 微软2 写一个函数,检查字符是否是整数,如果是,返回其整数值。
- 计算机笔试题:写一个函数,检查字符是否是整数,如果是,返回其整数值。(或者:怎样只用4行代码编写出一个从字符串到长整型的函数)