是否能任取前序、中序和后序两种序列建立二叉树?
前言
二叉树的遍历有三种方式,前序,中序和后序遍历都可以完成对二叉树的遍历。遍历一颗树很容易,那么建树呢?是否可以选择任意 2 种遍历序列来建立一颗二叉树。
分析
这三种遍历方式最为特殊就是中序遍历,中序遍历先遍历左子树后输出当前节点再遍历右子树,这种遍历方式可以保证当前位置的左边元素都是左子树的,右边的元素都是右子树的。前序序列的第一个元素为根节点,后序遍历的最后一个元素为根节点,配合中序遍历我们可以不断确定根节点从而建立二叉树,所以中序遍历配合后序或者前序就可以确认一颗二叉树,
那么前序和后序遍历配合能否建立二叉树呢?当然可以建立,不过这个二叉树无法唯一确定,因为前序和后序本质上都是将父节点和子节点进行分离,并没有指明左子树和右子树的能力。如果没有中序遍历来确定下一个根节点的方向,就可能出现下面这种情况:
上面两个二叉树的前序遍历都是2-1-3,后序遍历都是3-1-2,但是它们显然是不同的二叉树,所以根据先序序列和后序序列并不能唯一确定二叉树。(可以建树,不过结果可能不唯一)
实现
1、前序遍历和中序遍历建树
- 前序遍历数组的第一个元素就是当前二叉树的根节点
- 在中序序列找到该根节点,该根节点把中序序列分为左右子树两部分,确定左右子树长度
- 通过左右子树长度来确定左右子树的前序序列范围,前部分是左子树的前序序列,后部分是右子树的前序序列
- 同样的规则递归左右两个子树不断确定根节点
例如:
先序序列:1 2 3 4 5 6
中序序列:3 2 4 1 6 5 7
根据先序序列可以知道该根节点为1,那么找到中序序列中该根节点的位置 k,当前 k 为4 (1 2 3 4 5 6 7)
根据中序序列的特点,可知该位置的左边就是根节点的左子树,右边为根节点的右子树。(3 2 4 1 6 5 7)
接下来就要确定左右子树的前序和中序序列,不断缩小树的规模。
左子树的中序序列:il
到k-1
左子树的先序序列:pl+1
到k-il+pl
右子树的中序序列:k+1
到ir
右子树的先序序列:k-il+pl+1
到pr
通过这些序列后左子树和右子树就是一颗我们原来的树了,以同样的方法递归左右子树不断确定根节点就建立了一颗树
Code~
#include<bits/stdc++.h>
using namespace std;
int a[1005],b[1005];
struct Tree{Tree * l, *r;int val;
};
// [pl,pr] 前序序列开始和结束
// [il,ir] 中序序列开始和结束
// n 树的结点个数
Tree * build(int pl,int pr,int il,int ir,int n){if(n == 0) return NULL;Tree * root = new Tree();root->val = a[pl];int k = il;while(a[pl] != b[k]) k++;root->l = build(pl + 1, k - il + pl, il, k - 1, k - il);root->r = build(k - il + pl + 1, pr, k + 1, ir, ir - k);return root;
}
int main()
{int n;cin >> n;for(int i = 1; i <= n; i++){cin >> a[i];}for(int i = 1; i <= n; i++){cin >> b[i];}Tree * tree;tree = build(1,n,1,n,n);
}
2、后序遍历和后序遍历建树
后序遍历数组的最后一个元素就是当前二叉树的根节点
在中序序列找到该根节点,该根节点把中序序列分为左右子树两部分,确定左右子树长度
通过左右子树长度来确定左右子树的后序序列范围,前部分是左子树的后序序列,后部分是右子树的后序序列
同样的规则递归左右两个子树不断确定根节点
左子树的中序序列:il
到k-1
左子树的后序序列:pl
到k-il+pl-1
右子树的中序序列:k+1
到ir
右子树的后序序列:k-il+pl
到pr-1
同理递归左右子树不断确定根节点就建立了一颗树
#include<bits/stdc++.h>
using namespace std;
int a[1005],b[1005];
struct Tree{Tree * l,*r;int val;
};
// [pl,pr] 后序序列开始和结束
// [il,ir] 中序序列开始和结束
// n 树的结点个数
Tree * build(int pl,int pr,int il,int ir,int n){if(n == 0) return NULL;Tree * root = new Tree();root->val = a[pr];int k = il;while(a[pr] != b[k]) k++;root->l = build(pl, k - il + pl - 1, il, k - 1, k - il);root->r = build(k - il + pl, pr - 1, k + 1, ir, ir - k);return root;
}
int main()
{int n;cin >> n;for(int i = 1; i <= n; i++){cin >> a[i];}for(int i = 1; i <= n; i++){cin >> b[i];}Tree * tree;tree = build(1,n,1,n,n);
}
3、前序遍历和后序遍历建树
前序遍历,根节点在左右子树的前前面。而在后序遍历中,根结点在左右子树后面。
后序序列确定好根结点,该结点前面的序列按左子树右子树的顺序进行排列。
在前序序列以一个顶点作为根节点,提供其随后的节点A作为左子树根节点
在后序序列中找到该根节点A的位置,即可获取左子树的长度
确定好左右子树的前序和后序序列,即可以同样的规则递归左右两个子树不断确定根节点。
左子树的前序序列:pl+1
到pl+k-il+1
左子树的后序序列:pl
到k
右子树的前序序列:pl+k-il+1+1
到pr
右子树的后序序列:k+1
到ir-1
#include<bits/stdc++.h>
using namespace std;
struct node {int value;node *lchild, *rchild;
};
int n;
int pre[105], post[105];
map<int, int> mp;node *create(int pl, int pr, int il, int ir) {if (pl > pr) return NULL;if (pl == pr) {node* root = new node;root->value = pre[pl];root->lchild = root->rchild = NULL;return root;}node *root = new node;root->value = pre[pl];int k = mp[pre[pl + 1]];int numleft = k - il + 1;root->lchild = create(pl + 1, pl + numleft, il, k);root->rchild = create(pl + numleft + 1, pr, k + 1, ir - 1);return root;
}int main()
{cin >> n;for (int i = 0; i < n; i++){cin >> pre[i];}for (int i = 0; i < n; i++) { cin >> post[i]; mp[post[i]] = i; }node *root = create(0, n - 1, 0, n - 1);return 0;
}
前序和后序建树练习题:https://pintia.cn/problem-sets/994805342720868352/problems/99480535347086
参考资料:
https://blog.csdn.net/Mr_dimple/article/details/117046959 先序(后序)配合中序建树
https://blog.csdn.net/JasonRaySHD/article/details/104223642 前序序列与后序序列建树
是否能任取前序、中序和后序两种序列建立二叉树?相关推荐
- java如何获得键值_如何在java中取map中的键值 的两种方法
第一种方法根据键值的名字取值 import java.util.HashMap; import java.util.Map; public class Test { /** * @param args ...
- JAVA中如何取map的值_如何在java中取map中的键值 的两种方法
第一种方法根据键值的名字取值 import java.util.HashMap; import java.util.Map; public class Test { /** * @param args ...
- 二叉树深度优先 java_二叉树遍历(前序、中序、后序、层次、深度优先、广度优先遍历) java实现...
二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的.对于二叉树,有深度遍历和广度遍历,深度遍历有前序.中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历.由于树的 ...
- leetcode 106. 从中序与后序遍历序列构造二叉树 105. 从前序与中序遍历序列构造二叉树思考分析
目录 1.106题目 2.参考思路:递归切割数组 3.105题目 4.同样思路的代码 1.106题目 2.参考思路:递归切割数组 代码参考:公众号:代码随想录 后序数组+中序数组 以 后序数组(左右中 ...
- 【LeetCode笔记】94 144 145. 二叉树的前序、中序、后序遍历的迭代与递归(Java、dfs、迭代)
文章目录 一. 题目描述 二. 代码 & 思路 1. 递归的写法 2. 迭代的写法(本文重点来了) 1) 前序 2) 中序 3) 后序 直接来个整合吧,也方便看.之前只写了递归的,现在补上迭代 ...
- 二叉树遍历(前序、中序、后序、层次、深度优先、广度优先遍历)
二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的.对于二叉树,有深度遍历和广度遍历,深度遍历有前序.中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历.由于树的 ...
- 【必拿下系列】106. 从中序与后序遍历序列构造二叉树105从前序与中序遍历序列构造二叉树
两题各自的链接放这里了: 链接: 106 链接: 105 106.从中序与后序遍历序列构造二叉树 如果你是不知道理论的,那就得仔细分析了, 举个例子: 输入:inorder = [9,3,15,20, ...
- 树的基本概念和遍历规则 数据结构和算法 二叉树遍历(前序、中序、后序、层次、深度优先、广度优先遍历)
zsychanpin 博客园 首页 新随笔 联系 订阅 管理 树的基本概念和遍历规则 树的递归定义 树是n(n>0)个结点的有限集,这个集合满足下面条件: ⑴有且仅有一个结点没有前驱 ...
- 非递归实现二叉树的前序、中序、后序遍历
目录 非递归实现二叉树的前序遍历 非递归实现二叉树的中序遍历 非递归实现二叉树的后序遍历 根据二叉树的前序和中序遍历结果还原二叉树 根据二叉树的中序和后序遍历结果还原二叉树 非递归遍历需要借助栈. 非 ...
最新文章
- 吴恩达卷积神经网络课程——第一周笔记
- HTTP 错误 404.2 - Not Found
- 实战项目 10: 货物清单应用
- 【干货】接地气的产品设计流程
- android realmax sdk,RealMax推出全新开源AR SDK 框架ARToolKit
- Android Realm相关操作
- Rust从入门到放弃(1)—— hello,world
- php 异常 重试,Python中异常重试的解决方案详解
- python实时处理log文件脚本
- 《KAFKA官方文档》入门指南(二)
- html求相关系数,皮尔森相关系数怎么看 相关系数多少算具有相关性?
- html控制word打印在一张页面,HTML文件到WORD文档双面打印三步曲
- Kubernetes crictl管理命令详解
- 编辑表格用什么软件比较好?最好用的都在这了!
- html2:什么是超文本?
- 马云:2019年两大行业,会成就一批千万富翁!
- github上三个不错的开源框架
- 阿里云Redis开发规范学习总结
- ACM-SIAM离散算法研讨会SODA 2020今日召开
- 部署以太坊智能合约01