在这个问题之前,我们首先要弄清楚与二叉树三种遍历方法相关的几个问题。
一,二叉树遍历的定义和方式:
二叉树的遍历是指从根节点出发,按照某种次序访问二叉树中的所有结点,使得每个结点被访问一次且仅能被访问一次。遍历的本质也就是将非线性结构树线性化的过程。
那么二叉树有多少种遍历方式呢?
我们考虑到二叉树的组成可得出二叉树的遍历方式如下:
在这里我们只讨论限定先左后右的情况,即前序DLR,中序LDR和后序LRD。
二,前序中序后序序列的求法
已知二叉树的形态(结构),如何求它的前序序列,中序序列和后序序列?
这里给出这样一个二叉树:
三种方式的遍历结果如下:
- 前序序列:ABDGCEF
对于当前节点,先输出该节点,然后输出他的左孩子,最后输出他的右孩子。
输出A,接着左孩子;
输出B,接着左孩子;
输出D,左孩子为空,接着右孩子;
输出G,左右孩子都为空,此时A的左子树输出完毕,接着A的右子树;
输出C,接着左孩子;
输出E,接着右孩子;
输出F,遍历完毕。 - 中序序列:DGBAECF
对于当前结点,先输出它的左孩子,然后输出该结点,最后输出它的右孩子。
A有左孩子B,B有左孩子D,D无左孩子,故先按顺序输出此时的结点D和它的右孩子G;
目前B的左孩子全部输出完毕,我们输出B;
输出A;
A的左子树和A本身输出完毕,下面我们来观察A的右子树;
同样的道理,输出C的左子树E,输出C,输出C的右子树F;
至此该二叉树的所有结点都被访问到且都只被访问了一遍,中序遍历完毕。 - 后序序列:GDBEFCA
后序遍历与中序遍历类似,我这里就不再写了。
三,由已知序列得出二叉树结构
特别讨论1:只知道一种方式的遍历序列可以得出唯一的二叉树吗?
答案是否定的,例如我们已知某二叉树的前序遍历结果是ABC,那么我们不难得出此二叉树所有可能的结构:
特别讨论2:知道前序遍历的结果和后序遍历的结果可以得出唯一的二叉树吗?
不可以,例如我们已知某二叉树前序遍历结果是ABC,后序遍历结果是CBA,事实上这个二叉树是有4种可能结果的。
那么问题就来了,已知一种遍历序列不可能得到唯一的二叉树结构,在什么情况下已知任意两种遍历序列可以唯一确定一颗二叉树呢?
答:只要已知的这两种遍历序列包含一个中序序列就可以了。只知道前序序列和后序序列不可以的原因是先序—>根-左-右,后序—>左-右-根。若一棵树,其中一个或多个结点的左子树或右子树为空,那么此时无法判断到底是左子树为空还是右子树为空,就会出现两种情况。
现在我们回到原本的问题,由两个已知的遍历序列得到二叉树结构:给出这样一个问题:已知一颗二叉树的前序遍历序列和中序遍历序列分别是:ABCDEFGHI和BCAEDGHFI,如何构造二叉树?
分析:
前序的第一个元素必为根结点---->根结点A
中序根结点之前的元素是根结点的左子树,根结点之后的元素是根结点的右子树,即:
随后就可以根据元素在前序遍历和中序遍历的位置得出它们素的位置信息啦,具体如下图:
四,二叉树前序中序后序遍历的实现代码(递归)
贴出全部代码:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
struct BiTNode {
int data;
BiTNode *lchild;
BiTNode *rchild;
};
void create(BiTNode* &T){
int data;
cin >> data;
if (data != '\n') {
if (data == -1) {
T = NULL;
} else {
T = new BiTNode;
T->data = data;
create(T->lchild);
create(T->rchild);
}
}
}
void DLR(BiTNode* &T) {
// 先序遍历
if(T){
cout << T->data << " ";
DLR(T->lchild);
DLR(T->rchild);
}
}
void LDR(BiTNode* &T){
//中序遍历
if(T){
LDR(T->lchild);
cout << T->data << " ";
LDR(T->rchild);
}
}
void LRD(BiTNode* &T){
//后序遍历
if(T){
LRD(T->lchild);
LRD(T->rchild);
cout << T->data << " ";
}
}
int main(){
//注意,先输入所有的左子树,然后是右子树,没有左右孩子的用-1表示。
/*
测试二叉树:根是1,1的左子树2,1的右子树3,2的右子树4,3的左子树5
1
2 3
4 5
*/
BiTNode* T;
create(T);
cout << "前序遍历结果是:";
DLR(T);
cout << "\n";
cout << "中序遍历结果是:";
LDR(T);
cout << "\n";
cout << "后序遍历结果是:";
LRD(T);
cout << "\n";
return 0;
}