二叉树前序、中序、后序遍历

二叉树前序、中序、后序遍历

首先得知道什么是前序,中序,后序遍历:

前序遍历:
1.访问根节点
2.前序遍历左子树
3.前序遍历右子树
中序遍历:
1.中序遍历左子树
2.访问根节点
3.中序遍历右子树
后序遍历:
1.后序遍历左子树
2.后序遍历右子树
3.访问根节点

一、已知前序、中序遍历,求后序遍历

例:

前序遍历: GDAFEMHZ

中序遍历: ADEFGHMZ

步骤:
1 确定根,确定左子树,确定右子树。

2 在左子树中递归。

3 在右子树中递归。

4 打印当前根。

画树求法:

  • 第一步,根据前序遍历的特点,我们知道根结点为G

  • 第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。

  • 第三步,观察左子树ADEF,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为D。

  • 第四步,同样的道理,root的右子树节点HMZ中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。

  • 第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了

根据后序的遍历规则,我们可以知道,后序遍历顺序为:AEFDHZMG

二、已知中序和后序遍历,求前序遍历

依然是上面的题,这次我们只给出中序和后序遍历:

中序遍历: ADEFGHMZ

后序遍历: AEFDHZMG

画树求法:

第一步,根据后序遍历的特点,我们知道后序遍历最后一个结点即为根结点,即根结点为G。

第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。

第三步,观察左子树ADEF,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为D。

第四步,同样的道理,root的右子树节点HMZ中的根节点也可以通过前序遍历求得。在前后序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。

第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。

** 大体步骤差不多,主要是遍历方式的不同

输出结果:GDAFEMHZ

已知前序和后序求中序遍历

这样是不能得到一个唯一的二叉树出来的!

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->  1 /*
功能: 1.利用树的前序和中序序列创建树
2.利用树的后序和中序序列创建树
*/
#include <iostream>
#include <cstring>
using namespace std;

char pre[50] = "ABDHLEKCFG"; //前序序列
char mid[50] = "HLDBEKAFCG"; //中序序列
char post[50] = "LHDKEBFGCA"; //后序序列

typedef struct _Node
{
char v;
struct _Node *left;
struct _Node *right;
}Node, *PNode;

void PostTravelTree(PNode pn); //树的后序递归遍历
void PreTravelTree(PNode pn); //树的前序递归遍历
void PreMidCreateTree(PNode &pn, int i, int j, int len); //利用前序中序序列创建树
void PostMidCreateTree(PNode &pn, int i, int j, int len); //利用后序中序序列创建树
int Position(char c); //确定c在中序序列mid中的下标,假设树的各个节点的值各不相同


int main()
{
PNode root1 = NULL, root2= NULL;

PreMidCreateTree(root1, 0, 0, strlen(mid));
PostTravelTree(root1); cout<<endl;
PostMidCreateTree(root2, strlen(post)-1, 0, strlen(mid));
PreTravelTree(root2); cout<<endl;

return 0;
}


int Position(char c)
{
return strchr(mid,c)-mid;
}


/* 利用前序中序序列创建树,参考了http://hi.baidu.com/sulipol/blog/item/f01a20011dcce31a738b6524.html
*的实现,代码十分简洁,竟然只有短短的"令人发指"的8行,递归实在太彪悍了!!!!!!!!!!!!!!!!!!!!!
* i: 子树的前序序列字符串的首字符在pre[]中的下标
* j: 子树的中序序列字符串的首字符在mid[]中的下标
* len: 子树的字符串序列的长度
*/
void PreMidCreateTree(PNode &pn, int i, int j, int len)
{
if(len <= 0)
return;

pn = new Node;
pn->v = pre[i];
int m = Position(pre[i]);
PreMidCreateTree(pn->left, i+1, j, m-j); //m-j为左子树字符串长度
PreMidCreateTree(pn->right, i+(m-j)+1, m+1, len-1-(m-j)); //len-1-(m-j)为右子树字符串长度
}


/* 利用后序中序序列创建树
* i: 子树的后序序列字符串的尾字符在post[]中的下标
* j: 子树的中序序列字符串的首字符在mid[]中的下标
* len: 子树的字符串序列的长度
*/
void PostMidCreateTree(PNode &pn, int i, int j, int len)
{
if(len <= 0)
return;

pn = new Node;
pn->v = post[i];
int m = Position(post[i]);
PostMidCreateTree(pn->left, i-1-(len-1-(m-j)), j, m-j);//注意参数:m-j左子树的长度,len-1-(m-j)右子树的长度
PostMidCreateTree(pn->right, i-1, m+1, len-1-(m-j));
}


void PostTravelTree(PNode pn) //后序递归遍历
{
if(pn)
{
PostTravelTree(pn->left);
PostTravelTree(pn->right);
cout<<pn->v<<" ";
}
}


void PreTravelTree(PNode pn) //前序递归遍历
{
if(pn)
{
cout<<pn->v<<" ";
PreTravelTree(pn->left);
PreTravelTree(pn->right);
}
}