已知二叉树的中序和前序序列(或后序)求解树

序言

这种题一般有两种形式,共同点是都已知中序序列。如果没有中序序列,是无法唯一确定一棵树的,证明略。

已知二叉树的前序序列和中序序列

方法如下:

  1. 确定树的根节点。树根是当前树中所有元素在前序遍历中最先出现的元素。
  2. 求解树的子树。找出根节点在中序遍历中的位置,根左边的所有元素就是左子树,根右边的所有元素就是右子树。若根节点左边或右边为空,则该方向子树为空;若根节点左边和右边都为空,则根节点已经为叶子节点。
  3. 递归求解树。将左子树和右子树分别看成一棵二叉树,重复1、2、3步,直到所有的节点完成定位。

已知二叉树的后序序列和中序序列

  1. 确定树的根。树根是当前树中所有元素在后序遍历中最后出现的元素。
  2. 求解树的子树。找出根节点在中序遍历中的位置,根左边的所有元素就是左子树,根右边的所有元素就是右子树。若根节点左边或右边为空,则该方向子树为空;若根节点左边和右边都为空,则根节点已经为叶子节点。
  3. 递归求解树。将左子树和右子树分别看成一棵二叉树,重复1、2、3步,直到所有的节点完成定位。

举例说明

举个栗子:
中序序列 HLDBEKAFCG
后序序列 LHDKEBFGCA

  1. 在后序序列LHDKEBFGCA中最后出现的元素为A,HLDBEK|A|FCG
  2. 在后序序列LHDKEB中最后出现的元素为B,HLD|B|EK|A|FCG
  3. 在后序序列LHD中最后出现的元素为D,HL|D|B|EK|A|FCG
  4. 在后序序列LH中最后出现的元素为H,H|L|D|B|EK|A|FCG
  5. 在后序序列KE中最后出现的元素为E,H|L|D|B|E|K|A|FCG
  6. 在后序序列FGC中最后出现的元素为C,H|L|D|B|E|K|A|F|C|G
  7. 所有元素都已经定位,二叉树求解完成。
    1
    2
    3
    4
    5
    6
    7
    8
    9
            A
    / \
    B C
    / \ / \
    D E F G
    / \
    H K
    \
    L

参考代码

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
/*
功能: 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 = NULL;
struct _Node *right = NULL;
}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; //先序
system("pause");
return 0;
}


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


/* 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);
}
}