常见算法基础题思路简析(三)-二叉树篇
2017-09-28 22:08
323 查看
常见算法基础题思路简析(三)-二叉树篇
标签: algorithms常见算法基础题思路简析三-二叉树篇
判断是否为平衡二叉树
判断是否为完全二叉树
找出搜索二叉树中换位的两个节点
打印纸的折痕
二叉树整棵树上节点间最大距离
找到含有节点最多的搜索二叉子树
按层打印二叉树并换行
递归方式实现二叉树的先序中序和后序的遍历
非递归方式实现二叉树的先序中序和后序的遍历
先序遍历
中序遍历
后序遍历
本文对和 二叉树 有关的常见算法基础题思路分类进行分析和总结,并以 Java 为例,适当指出需要注意的编程细节
相关题目和代码在 GitHub: https://github.com/brianway/algorithms-learning
题目见
com.brianway.learning.algorithms.lectures.binarytree包
判断是否为平衡二叉树
题目见CheckBalance
思路:
判断左子树是否为平衡二叉树,是则返回高度,不是返回 -1
判断右子树是否为平衡二叉树,是则返回高度,不是返回 -1
若左右子树均时平衡二叉树,则看两者高度差是否大于 1。是则返回 -1,不是则取两者中大的再加上 1
注意:
这里对返回值意义复用了,非负数则表示高度,负数表示不是平衡二叉树
判断是否为完全二叉树
题目见CheckCompletion
思路:
使用队列,按层遍历二叉树,分以下几种情况依次判断:
如果只有右孩子,返回 false
如果已经遍历过最后一个非叶子节点,当前节点还是非叶子节点,返回 false
如果左孩子非空,入队
如果右孩子非空,入队;如果右孩子空,表示该节点应为最后一个非叶子节点
若遍历完,则是完全二叉树
找出搜索二叉树中换位的两个节点
题目见FindErrorNode
思路:
中序遍历二叉树,找到出现降序的节点。第一次出现降序的较大值为换位的两个节点中的较大值,最后一次降序的较小值为换位节点中的较小值
注意:
可能出现一次降序,可能出现两次降序。
若出现一次降序,则这两个值就是换位节点;
若出现两次降序,则第一次降序的较大值和第二次降序的较小值为换位节点
可以用非递归方式中序遍历二叉搜索树来实现
打印纸的折痕
题目见FoldPaper
思路:
使用一个队列才存结果
每个 fold 里,先递归调用 fold,再将当前折痕方向入队,再递归调用 fold
从队列依次取出折痕即可
注意:
每个 fold 里的前后两次调用,方向相反,一上一下,和折纸方向有关
二叉树整棵树上节点间最大距离
题目见LongestDistance
思路:
递归的调用 find,每步迭代更新这两个值(当前子树的节点最大距离,到当前子树根结点的最大长度):(MaxLength,MaxToRoot),并将其返回
当前的 MaxToRoot = max(左子树的 MaxToRoot,右子树的 MaxToRoot) + 1
当前的 MaxLength = max(一边的最大距离,两边的最大距离)
一边的最大距离 = max(左子树的 MaxLength,右子树的 MaxLength)
两边的最大距离 = 左子树的 MaxToRoot + 右子树的 MaxToRoot + 1
注意:
需要返回两个值,所以用数组当返回类型
分类/划分标准和思路理清了,代码很简单
找到含有节点最多的搜索二叉子树
题目见MaxSubtree
思路:
需要记录满足条件搜索二叉树的最大值,最小值,节点个数,记为数组
info[],并返回该搜索二叉树的根节点
每一步递归对左孩子和右孩子调用,然后分情况讨论
左孩子的调用结果是左孩子,右孩子的的调用结果是右孩子,且左右孩子和根节点满足大小关系,更新上述
info[],返回根节点
不满足上面的条件则从左右调用结果中选择节点个数大的结果(题目要求),更新上述
info[],返回调用结果
左右节点个数相等,选择根结点值大的,更新上述
info[],返回调用结果
注意:
空节点判断,数组初始化(最大值,最小值,个数0)
更新
info[]时,尤其对情况一,需要判断左右孩子是否为空的情况
按层打印二叉树并换行
题目见TreePrinter
思路:
使用队列,先将根节点入队
使用两个指针 last 和 nlast 分别代表当前行的最后一个节点和下一行的最后一个节点,初始值均为 root
每次从队列取出一个节点,并将其左右节点入队,每入队一个,更新 nlast 为入队的节点
判断当前取出的节点是否为 last,若是,则说明这时此行最后一个,故更新 last = nlast
注意:
每出队一个节点,入队其左右孩子,这里 每次 都需要更新 nlast,因为不知道下一行在何时开始没新节点加入
结尾条件需要注意,只有当前节点为 last 且此时队列还非空时,才进行 last 的更新,同时换行,非空这个需要判断,否则会多出一个空行
递归方式实现二叉树的先序、中序和后序的遍历
一定是先左后右,先序、中序和后序指的是根节点遍历的先后题目见
TreeToSequence
思路:
递归调用即可,终止条件是该节点为 null
不为 null,则将二叉树的“左”,“根”,“右”按遍历顺序的要求打印
注意:
没啥注意的,三四行代码就完了
非递归方式实现二叉树的先序、中序和后序的遍历
题目见TreeToSequence2
都是使用 栈 来实现的
先序遍历
思路:有点像深度优先遍历使用一个栈,先将根节点压栈,当栈非空时进行以下步骤
每次出栈一个节点,并先将其右孩子压栈,再将其左孩子压栈
注意:
利用栈“后进先出”的特性,使得右孩子会在左孩子之后出栈
中序遍历
思路:使用栈,先将根节点入栈,当栈非空时进行以下步骤
当当前节点和其左孩子均不为空时,将其左孩子入栈,当前节点指向左孩子
当当前节点为空或者左孩子为空时,从栈顶取出一个,并将当前节点指向右孩子(可能为空)。若该取出的节点有右孩子,则将右孩子入栈。
注意:
“当前节点左孩子为空则出栈”用于触发左子树到顶的情况
“当前节点为空则出栈”用于触发右孩子为空的回退
后序遍历
思路:核心在于使用最近访问节点 last 来标记是从左孩子还是右孩子遍历完返回的,从而确定是入栈还是出栈使用栈,先将根节点入栈,当栈非空时进行以下步骤
每次查看栈顶节点(但不出栈),根据栈顶节点的情况分类判断:
左孩子非空且上次访问既不为左孩子也不为右孩子,则左孩子入栈
否则,若右孩子非空且上次访问不为右孩子,则右孩子入栈
否则,表示此时左右孩子均为空或均访问过,栈顶出栈,并记为最近访问节点 last
注意:
按上面的逻辑左孩子出栈后,右孩子才会入栈,所以是先左后右的顺序
右孩子是上次访问的节点时,前两条都不满足,所以一定会是孩子的根结点出栈
作者@brianway更多文章:个人网站
|CSDN
|oschina
相关文章推荐
- 常见算法基础题思路简析(三)-二叉树篇
- 常见算法基础题思路简析(一)-排序篇
- 常见算法基础题思路简析(五)-队列和栈篇
- 常见算法基础题思路简析(六)-字符串篇
- 常见算法基础题思路简析(六)-字符串篇
- 常见算法基础题思路简析(一)-排序篇
- 常见算法基础题思路简析(一)-排序篇
- 常见算法基础题思路简析(二)-链表篇
- 常见算法基础题思路简析(二)-链表篇
- 常见算法基础题思路简析(四)-二分搜索篇
- 常见算法基础题思路简析(四)-二分搜索篇
- 常见算法基础题思路简析(五)-队列和栈篇
- C#附加数据库算法及思路,包括附加、还原、备份、分离、压缩、创建、修改等常见操作(修正)
- 基础算法记录(二)——部分常见算法问题
- 常见的GC垃圾收集算法的思路
- 常见基础算法大集合(C语言实现)
- 传说中的15道常见的基础算法题java解法
- 常见算法基础之排序
- 第一章:算法设计基础(思维体操+常见策略+高效算法+动态规划)
- 常见算法与思路