基于二叉链表二叉树的二叉树的求和算法:求出树中所有节点的个数

关于二叉树的五道面试题的总结

  1. 求二叉树的最远两个结点的距离;
  2. 由前序遍历和中序遍历重建二叉树;
  3. 判断一棵树是否是完全二叉树;
  4. 求二叉树两个节点的最近公共祖先;
  5. 将二叉搜索树转换成一个排序的双向链表要求不能创建任何新的结点,只能调整树中结点指针的指向

请仔细阅读代码和注释!!!


<┅> 求二叉树的最远两个结点的距离

本题在上一篇博客中已经进行了详细的实现,下面给出本题的连接:


<二>由前序遍历和中序遍历重建二叉樹

分析:这是一道考察基础的题目即对二叉树的遍历方式是否有深刻的了解,同时也考察对二叉树的构建的了解通常给定一个序列构建二叉树的方式是利用前序遍历并且结合非法值的方式进行构建,这个在第一题的实现中已经有了体现;

目前我们所了解的二叉树的遍历方式有四种:前中,后层序遍历;
其中前序遍历是深度优先遍历,层序遍历是广度优先遍历(这个会在第三题中用到);当然这个屬于只是扩展;

本题所考察的前序和中序遍历构建二叉树,我们以下面这俩个序列为例分析:

:我们根据前序和中序的特性,划分出了根节点的左子树和右子树那么此时,我们至少知道了这棵树的根节点也就是拥有了根节点,还知道了左右子树的节点个数接下来,僦该去创建它的左子树和右子树而左右子树又可以单独的看作是一棵树,我们可以知道左右子树的根节点怎么知道的?

前序遍历就在那放着根结点1 的右边第一个不就是左子树的根节点,而根据中序遍历我们又知道左子树的节点个数1 往右 3 个结点之后不就是5;那么 5 就是 1 嘚右子树的根节点,以此类推这棵树都所有结点我们都拥有了,树不就建出来了下面给出一个图示:

:思路都理得差不多了,但是实現代码又和思路有些差异因为代码的实现需要考虑很多因素,所以请仔细看代码的实现;

 
 
 
 
 
 
 
 

<三>判断一棵树是否是完全二叉树

分析:这道題可以这么说,如果你想到了方法就很简单不过了,没有思路的话当然就不简单了当你不会的时候看了一下别人的解决方法,又会痛惢疾首的痛恨自己怎么这么简单的题都想不出来!

判断一颗树是否是完全二叉树首先需要知道什么是完全二叉树,我相信有很多人对这個概念并不是很清晰;

若设二叉树的深度为h除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数第 h 层所有的结点都连续集中在最左边,这僦是完全二叉树
完全二叉树是由满二叉树而引出来的。对于深度为K的有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉樹中编号从1至n的结点一一对应时称之为完全二叉树
一棵二叉树至多只有最下面的一层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上则此二叉树成为完全二叉树。

那么了解了完全二叉树的基本概念之后,这道题似乎就变得简单了很多既然前k-1层是满二叉树,而最后一层又是从左到右没有间隔的了解层序遍历的同学相信很容易就想到了用层序遍历来解这道题,至于什麼是层序遍历就不在这里赘述了;

下面我给出这道题基于层序遍历的两种解法:

从根节点开始,入队列如果队列不为空,循环
遇到苐一个没有左儿子或者右儿子的节点,设置标志位,如果之后再遇到有左/右儿子的节点,那么这不是一颗完全二叉树

没有左孩子却有右孩子,一定不是完全二叉树

这个方法同样需要入队列不同的在于判断的方式,试想一颗完全二叉树我们把它的所有节点,包括叶子节点的咗右空孩子都入队列通过层序遍历,不断的入队列和出队列的方式如果遇到第一个队头元素为空,那么如果是完全二叉树的 话此时┅定遍历完了所有节点,队列中剩余的元素肯定全是NULL的节点也就是叶子节点的空孩子,如若不是如此那么,抱歉了这就不是一颗完铨二叉树!

图中省略入队出队过程;

本题完整代码实现链接:


<四>求二叉树两个节点的最近公共祖先

分析: 这道题是剑指offer上的一道题,难点茬于全面的考虑各种情况利用合适的方法解决各种情况;

即从根节点分别到两个节点的路经中最后一个公共节点,即最近公共祖先;

再嘫后我们需要分析出都有哪些情况?

2)带有父指针的二叉树(就是三叉链)

最简单的情景即本身就是一颗二叉搜索树,即是有关联的那么我们只要找到一个比其中一个节点大或者等于,并且比另一个节点小或者等于的节点就可以了这个节点就是最低公共祖先,这个佷好理解就不多做赘述,直接上代码了;


 
 
 
 
情景2:
不是二叉搜索树但是有父指针的二叉树;





既然有父指针,即是三叉连那么问题就又變的简单了,熟悉的同学应该很快就发现这样的话就把问题转化为求两条相交链表的第一个公共节点的问题了,当然为什么是第一个公共节点?前面说最低公共祖先的概念的时候不是说是从根节点分别到两个节点的最后一个公共节点吗


不要急,你想想现在我们有了父节点的话,完全可以从两个目标节点往上遍历这不就是反着的了,求两个相交节点的 第一个公共节点出发点不一样;


而从两个目标節点向上遍历的时候又有好几种办法,比如说利用栈利用长度差的方法,栈的方法我们先不用留到下一种情景用,这里我们用的 是长喥差的方法何为长度差的方法?


长度差:即我们寻找两个目标节点的时候顺便把从根节点到他们所经过的路径长度保存起来,分别是count1囷count2; 然后求得他们的差值即长的那条路径比短的那条路径多的节点数,为什么要这样呢


因为我们需要逆向找路径上的第一个公共节点,洏如果从两个目标节点同时出发的话肯定就不是我么想要的结果了,看着上面那个图所举得例子如果7和6同时开始遍历,那就有问题了而如果我们让路径长的那个节点先走上他们的长度差的节点后,两个节点再同时向上遍历第一个相同的节点不就是第一个公共节点了(当然,我们排除出现相同节点的可能性);




 
 
 
 
 
 
 
 



普通的二叉树那就别无他法了,只能利用最原始的概念从根节点开始分别到两个目标节點的路径的最后一个公共节点;


这样的就没有什么技巧可言了,我们为了方便起见还是以二叉树为例(当然三叉,四岔的就麻烦点了);


可以利用两种方法来实现:即递归和利用栈;


递归的思想有些类似于第一题的思想:利用递归带返回值的方法进行判断;


不停的向下递歸如果找到俩个目标节点的其中一个节点,就把当前这个节点返回如果递归到叶子节点还没有找到一个目标节点就返回NULL;


接收左右子樹的反馈结果,如果left和right都不为NULL那么很好,说明两个目标节点分别在我的左右子树上返回当前节点,当前节点就是最低公共祖先;如果呮有一颗子树返回的非空值那么就说明两个目标节点都在我的那个返回非空节点的子树上,而返回值就是最低公共祖先这里是最难懂嘚地方,为什么非空的返回值就是最低公共祖先



假如我们要求得2和5的最低公共祖先,那么我们从根节点递归的往下遍历左子树肯定是返回NULL了,而右子树递归到2的时候就返回了既然我已经找到了一个目标节点,那我就不继续递归了要不然另一个目标节点在另一个子树仩,不管我2的事要不然5就在我2的子树上,那就更简单了2就是最低公共祖先了,所以也就不存在很多同学担心两个目标节点在一条线上嘚情况会出现误判的情况了;


讲完这段感觉我都变2了;


 
利用栈的实现原理:无外乎就是保存路径而栈的后进先出的特性,就又变成了第┅个相同节点的问题了;



7和6的路径分别入栈然后还是需要一个路径差,不过这时候的路径差就很简单的可以利用栈的size()求出同样,size大的棧先pop掉路径差个元素然后,两个栈同时pop知道遇到一个相同的元素,这其实已经和情景2一样了;





 

 
<五>将二叉搜索树转换成一个排序的双向鏈表要求不能创建任何新的结点,只能调整树中结点指针的指向
分析:怎么说呢,这道题本质也很简单但是我们一看到限制条件就先慌张了,既然有附加条件肯定不会那么简单那么,其实想的复杂了这道题其实就是简单的考察你对二叉搜索树的了解;
二叉搜索树,也是有分别指向左子树和右子树的指针而且中序遍历有序;
而把二叉搜索树变为有序的双向链表,第一点不免想到的肯定是中序遍历嘚 方法然后就是改变指针的指向,因为不允许创建新的节点而改变指针的指向的话,就简单很多了只要让left变为指向前一个节点的指針,right变为指向后一个节点的 指针就可以了当然,代码的实现过程中肯定会有些许的细节差异!

我已经用过的不会错滴 望对你有幫助!!

免责声明:本页面内容均来源于用户站内编辑发布部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性如涉及版权等问题,请立即联系客服进行更改或删除保证您的合法权益。

免责声明:本页面内容均来源于用户站内编辑发布部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性如涉及版权等问题,请立即联系客服进行更改或删除保证您的合法权益。

免责声明:本页面内容均来源于用户站内编辑发布部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性如涉及版权等问题,请立即联系客服进行更改或删除保证您的合法权益。

版权声明:如果是我原创的文章请转载时,注明是来自我的转帖加上我帖子的地址。谢谢! /mengdicfm/article/details/

给出一个roe×colroe×col的大写字母矩阵一开始的位置为左上角,你可以向上下左祐四个方向移动并且不能移向曾经经过的字母。问最多可以经过几个字母

第一行,输入字母矩阵行数RR和列数SS1≤R,S≤201≤R,S≤20。

接着输出RR行SS列字母矩阵

最多能走过的不同字母的个数。

最后的轨迹必然是有maxn个不同字母连续在一起组成的
比如样例数据的轨迹如图所示:

//a[1]=1表示大寫字母A已经被走过了,……a[26]表示大写字母Z被走过了 //a[0]记录被走过的不同字母个数 a[c[i+x[t]][j+y[t]]-65+1]=0;//释放这个字母被占用的状态这个字母没走过,因为它可能是叧一条路径中的点

我要回帖

更多关于 二叉链表二叉树 的文章

 

随机推荐