前言:

前几天在温习《编程之美》这本书的时候,看到了二叉树的重建。正好,也想复习一下数据结构的知识,就来写了一个小Demo。居然有新发现(本文中的第三种方式)。

我们在学习数据结构的时候,肯定可以很轻松地编写对二叉树的三种遍历过程。分别是前序、中序和后序遍历。

这里要说的不是对二叉树遍历,而是要通过一些遍历过程来重建一棵二叉树。比例,告诉你有一棵二叉树前序遍历的结果为:ABC;中序遍历的结果为:BAC。我们可以很轻松地写出这棵二叉树就是以A为根节点、其左孩子是B、右孩子是C。那么从代码的角度,或者说是从算法的角度又要怎么来编写程序呢?

商业转载请联系作者获得授权,非商业转载请注明出处。
本文作者:Q-WHai
发表日期: 2015年10月24日
本文链接:https://qwhai.blog.csdn.net/article/details/49798221
来源:CSDN
更多内容:分类 >> 算法与数学

二叉树的遍历过程:

图-1 二叉树的前序遍历

图-2 二叉树的中序遍历

图-3 二叉树的后序遍历

思路说明:

这里我会采用三种不同的方法来说明其重建过程,代码部分则是采用其中一种来作详解。

而具体数据如下:

前序:A B D E H I C F G
中序:D B H E I A F C G

1.递归重建

在上面的前序序列中,我们可以很容易地获得A就是根节点。此时,我们可以在后序序列中找到这个A,那么在A的左边就是A的左孩子及其子节点,在A的右边就是A的右孩子及其子节点。假设,我们目前在A的左边。在遍历前序序列到B的时候,我就知道了B就是A的左孩子,而在B的左边(中序序列)的都是B的左孩子及其子节点,在B的右边(同是也在A的左边)的就是B的右孩子及其子节点...以此类推.这就是利用递归来重建二叉树。

2.建立节点集

关于这种方法,如果你对B树有所了解,也就不难理解了。因为后面我会单独写一篇关于B树的文章,这里就暂时一笔代过,说说思路就好了。

为子节点建立节点集。在遍历(前/后序遍历的序列)的过程中,分裂和修正这个节点集。

3.创建索引函数

前面的两种方法,其实可以说是同一种方法,也是比较常见的方法,《编程之美》里使用的正是常见的递归调用。下面的这种方法是本文的重点,我在其他地方并没有见到过类似的方法,于是在此记录一下思路和过程。我当时也只是灵光一闪,想到还可以用这样巧妙的方法来实现。真是让人兴奋。下面看看具体实现过程。

让前/后序遍历的序列拥有中序遍历序列的索引,在遍历(前/后序遍历的序列)的过程中按照二叉排序树的方法直接插入即可.

图-4 节点索引函数对照表

看到这个表,是不是有一种似曾相识的感觉。这个在KMP模式匹配也有一个类似的INDEX函数,在KMP里叫作next.这里我给他取名叫作index吧。因为这个index很直观,就是取了某一个节点的下标,并保存。

其实在已知的遍历序列中,如果含有中序遍历结果,那么我们都可以采用上面的这种创建索引函数的方式来简化重建过程。可能你会问我为什么会这样?下面请看图-4.

图-5 二叉树的中序遍历顺序示意图

我们可以把图-2中的中序遍历二叉树过程平摊开,就可以获得图-5中这样的一个顺序序列。

从上面的图-5中我们可以发现一个现象,那就是某一个节点的左孩子一定是在这个节点的左边,其右孩子一定是在这个节点的右边(当然,这个现象也可以从中序遍历的定义获得)。也就是节点Node的左孩子Left的值一定是比Node的值小,而Node右孩子Right的值一定是比Node的值大。

这样的一些描述是不是似曾相识呢?没错,在二叉排序树中正是这样定义的。

现在,我们再来看看二叉树的前序遍历过程。因为是前序,所以我们在遍历节点Node的孩子节点之前,必定是已经遍历过Node的孩子节点。这样也可以理解成是一种临近遍历的过程。

这样看来,前序 + 中序 = 二叉排序树。于是,我们就有了以下代码:

节点(Node):

public class Node {String name;Node leftNode;Node rightNode;int index;public String getName() {return name;}public void setName(String name) {this.name = name;}public Node getLeftNode() {return leftNode;}public void setLeftNode(Node leftNode) {this.leftNode = leftNode;}public Node getRightNode() {return rightNode;}public void setRightNode(Node rightNode) {this.rightNode = rightNode;}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}
}

主函数(RestoreBinTree):

public class RestoreBinTree {Node root = null;public static void main(String[] args) {RestoreBinTree m = new RestoreBinTree();String[] F = {"A", "B", "D", "E", "H", "I", "C", "F", "G"};String[] L = {"D", "B", "H", "E", "I", "A", "F", "C", "G"};m.restoreTree(F, L);System.out.println(m.root);}/*** 重建二叉树* @param labelFirst* @param labelLast*/public void restoreTree(String[] labelFirst, String[] labelLast) {int[] r = recordArray(labelFirst, labelLast);if (root == null) {root = new Node();root.setName(labelFirst[0]);root.setIndex(r[0]);}for (int i = 1; i < labelFirst.length; i++) {Node currentNode = new Node();currentNode.setName(labelFirst[i]);currentNode.setIndex(r[i]);insert(currentNode);}}/*** 向二叉树中插入一个节点* @param insertNode*/public void insert(Node insertNode) {Node currentNode = root;while (true) {if (insertNode.getIndex() < currentNode.getIndex()) {if (currentNode.getLeftNode() == null) {currentNode.setLeftNode(insertNode);break;} else {currentNode = currentNode.getLeftNode();}} else if (insertNode.getIndex() > currentNode.getIndex()) {if (currentNode.getRightNode() == null) {currentNode.setRightNode(insertNode);break;} else {currentNode = currentNode.getRightNode();}} else {break;}}}/*** 计算索引函数* @param labelFirst* @param labelLast* @return*/public int[] recordArray(String[] labelFirst, String[] labelLast) {if (labelFirst == null || labelFirst.length == 0 || labelLast == null || labelLast.length == 0) {return null;}int[] record = new int[labelFirst.length];for (int i = 0; i < labelFirst.length; i++) {record[i] = index(labelLast, labelFirst[i]);}return record;}/*** 计算索引函数* @param labels* @param label* @return*/private int index(String[] labels, String label) {for (int i = 0; i < labels.length; i++) {if (label.equals(labels[i])) {return i;}}return -1;}
}

REF:

《编程之美》

Github

https://github.com/qwhai/simple-tree

数据结构:关于重建二叉树的三种思路相关推荐

  1. 【数据结构】理解二叉树的三种遍历--前序、中序、后序 +层序(简明易懂)

    一.易懂的形象理解 其实从名字就可以很好的理解这三种遍历,我在第二点时候说,但是估计能翻到我的文的同学们之前肯定看过好多类似的了,那咱们换个思路~ 先用我想的一种简单易懂的形象思维理解一下前序.中序. ...

  2. 【数据结构】翻转二叉树的三种方式

    一.分析 理解递归思想的条件下很容易想到解题思路,当然可能有人会有疑问,那什么情况下知道使用递归呢,有个最简单的办法如果算法里需要重复循环用同一个思路执行得到结果,那么必然可以使用递归.进行翻转本质上 ...

  3. 二叉树----数据结构:二叉树的三种遍历及习题

    二叉树----数据结构:二叉树的三种遍历,利用递归算法. 关于二叉树的遍历,应用非常广泛,不单单是访问打印结点,还可以进行一系列的操作,如赋值.删除.查找.求二叉树的深度等等. 有递归和非递归两种算法 ...

  4. C语言基本数据结构之二(二叉树的三种遍历,节点数以及深度算法)

    关于二叉树的定义,网上有比较好的介绍,在这里就简单介绍二叉树的一些性质 二叉树的基本性质 1)二叉树的第i层上至多有 2^(i-1)(i ≥1)个结点: 2)深度为 h 的二叉树中至多含有 2^h – ...

  5. 二叉树的三种遍历(递归与非递归) + 层次遍历

    <转载于  >>> > 二叉树是一种非常重要的数据结构,很多其他数据机构都是基于二叉树的基础演变过来的.二叉树有前.中.后三种遍历方式,因为树的本身就是用递归定义的,因此 ...

  6. c语言中二叉树中总结点,C语言二叉树的三种遍历方式的实现及原理

    二叉树遍历分为三种:前序.中序.后序,其中序遍历最为重要.为啥叫这个名字?是根据根节点的顺序命名的. 比如上图正常的一个满节点,A:根节点.B:左节点.C:右节点,前序顺序是ABC(根节点排最先,然后 ...

  7. 求两个链表的第一个公共结点各种情况及三种思路分析

    转自:http://blog.csdn.net/ssopp24/article/details/72377184 1.寻找两个链表的第一个公共结//这道题可以有很多种思路, 我们按照, 有坏到好的顺序 ...

  8. c语言二叉树的遍历菜单系统,C语言二叉树的三种遍历方式的实现及原理

    C语言二叉树的三种遍历方式的实现及原理 发布时间:2020-10-03 19:43:57 来源:脚本之家 阅读:63 作者:看雪. 二叉树遍历分为三种:前序.中序.后序,其中序遍历最为重要.为啥叫这个 ...

  9. Python培训讲解二叉树的三种深度

    python代码实现了二叉树,这次将会实现二叉树的几种遍历方法,来更好的解析二叉树的结构特点.分别是一种广度遍历,和三种深度遍历方法:先序遍历,中序遍历,后序遍历.下面是代码实现: 1.先序遍历 遍历 ...

最新文章

  1. Powershell获取当前机器的序列号用户名域
  2. java pl0 四元式,【编译原理】c++实现自下而上语法分析及中间代码(四元式)生成...
  3. Dlib学习笔记:解决dlib array2d转 OpenCV Mat时颜色失真
  4. IIS 部署asp.net Provisional headers are shown 在VS2005返回值,部署不返回值
  5. 12条守则:让你成功创业当老板
  6. 如何使用并解释通过 vSAN 监测收集的性能统计信息 (2064240)
  7. 又忙了一天,什么书也不看。
  8. 环境变量的配置导致无法登录
  9. Ubuntu搜狗输入法乱码
  10. MFC中显示一张位图
  11. BZOJ 2957 分块
  12. LoRaWAN协议格式
  13. 这样来理解委托,代理,协议三者的区别
  14. 速记JVM内存模型和垃圾回收策略
  15. 【小牛分享】人员组织架构图 - 为纪念2013即将结束而分享
  16. 史上最全! 全球 22 种开源商业收入模式
  17. 谷粒商城分布式高级篇总结文档
  18. 视频AI融合视频平台(LiveMedia视频监控平台)
  19. Go初学者坑记之 go mod init 和自定义包的使用
  20. python range函数步长什么意思

热门文章

  1. C++ Primer 5th笔记(chap 13 拷贝控制) 实例2内存管理
  2. c++服务器开发学习--02--MySQL,Redis,ASIO,iocp,TrinityCore代码结构,c++对象模型
  3. 解决kubectl get pods时 No resources found.问题
  4. SQL语法之基础查询(进阶1)and条件查询(进阶2)
  5. 9、创建索引(CREATE INDEX)
  6. 二叉树的深搜(DFS)与广搜(BFS)
  7. 【PAT乙级】 1015 德才论 (25 分)
  8. 项目: 互动粒子仿真
  9. 接口自动化-发送get请求-1
  10. Spring boot显示登录用户