关于二叉树的五道面试题的总结
- 求二叉树的最远两个结点的距离;
- 由前序遍历和中序遍历重建二叉树;
- 判断一棵树是否是完全二叉树;
- 求二叉树两个节点的最近公共祖先;
- 将二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
请仔细阅读代码和注释!!!
<一> 求二叉树的最远两个结点的距离
本题在上一篇博客中已经进行了详细的实现,下面给出本题的连接:
<二>由前序遍历和中序遍历重建二叉树
分析:这是一道考察基础的题目,即对二叉树的遍历方式是否有深刻的了解,同时也考察对二叉树的构建的了解,通常给定一个序列构建二叉树的方式是利用前序遍历并且结合非法值的方式进行构建,这个在第一题的实现中已经有了体现;
目前我们所了解的二叉树的遍历方式有四种:前,中,后,层序遍历;
其中前序遍历是深度优先遍历,层序遍历是广度优先遍历(这个会在第三题中用到);当然,这个属于只是扩展;
本题所考察的前序和中序遍历构建二叉树,我们以下面这俩个序列为例,分析:
(前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5)
:我们根据前序和中序的特性,划分出了根节点的左子树和右子树,那么此时,我们至少知道了这棵树的根节点,也就是拥有了根节点,还知道了左右子树的节点个数,接下来,就该去创建它的左子树和右子树,而左右子树又可以单独的看作是一棵树,我们可以知道左右子树的根节点,怎么知道的?
前序遍历就在那放着,根结点1 的右边第一个不就是左子树的根节点,而根据中序遍历我们又知道左子树的节点个数,1 往右 3 个结点之后不就是5;那么 5 就是 1 的右子树的根节点,以此类推,这棵树都所有结点我们都拥有了,树不就建出来了,下面给出一个图示:
:思路都理得差不多了,但是实现代码又和思路有些差异,因为代码的实现需要考虑很多因素,所以,请仔细看代码的实现;
代码:
//前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5
//在没有重复节点的前提下
Node* _GreatTree(int* prestart, int* preend,int* inarrstart,int* inarrend)
{
Node* root = new Node(*prestart);
//如果只有当前一个节点,则将创建好的这个节点返回;
if(prestart == preend && inarrstart == inarrend)
return root;
//找到中序遍历中的根节点
int* rootInorder = inarrstart;
while(rootInorder <= inarrend && *prestart != *rootInorder)
++rootInorder;
//创建左子树
int lenth = rootInorder - inarrstart; //左子树的节点数量
int* leftpreend = prestart+lenth; // 左子树前序遍历节尾
//如果在当前根节点有左子树,进行创建左子树
if(lenth > 0)
root->_left = _GreatTree(prestart+1,leftpreend,inarrstart,rootInorder);
//创建右子树
int* rightprestart = leftpreend+1; //右子树前序遍历的开始
//如果当前根节点有右子树,则创建右子树;
if(lenth < preend - prestart)
root->_right = _GreatTree(rightprestart,preend,rootInorder+1,inarrend);
return root;
}
<三>判断一棵树是否是完全二叉树
分析:这道题可以这么说,如果你想到了方法,就很简单不过了,没有思路的话当然就不简单了,当你不会的时候看了一下别人的解决方法,又会痛心疾首的痛恨自己怎么这么简单的题都想不出来!
当然,以上纯属废话;
判断一颗树是否是完全二叉树,首先需要知道什么是完全二叉树,我相信有很多人对这个概念并不是很清晰;
完全二叉树(Complete Binary Tree)
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
一棵二叉树至多只有最下面的一层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树。
例如下面这棵树:
那么,了解了完全二叉树的基本概念之后,这道题似乎就变得简单了很多,既然前k-1层是满二叉树,而最后一层又是从左到右没有间隔的,了解层序遍历的同学相信很容易就想到了用层序遍历来解这道题,至于什么是层序遍历,就不在这里赘述了;
下面我给出这道题基于层序遍历的两种解法:
1)设置标志法
从根节点开始,入队列&#