数据结构进阶实训九 二叉树的应用

数据结构进阶实训九 二叉树的应用

Data structure advanced training course notes and algorithm exercises

Source Code: https://github.com/MysticalGuest/DataStructure/tree/master/AdvancedJuniorTraining


题目1

1
2
3
4
5
建二叉树二叉链表存储
- 扩展的先序序列(之前采用的方法)
此次要求:已知两个遍历序列建二叉树(先/中,后/中)
- 其先、中序遍历序列分别存放在两个数组pre[]和inorder[]中。
- 其中、后序遍历序列分别存放在两个数组inorder[]和post中。

1.1 算法设计思想

两种建树的思想相同,都是分治的思想;
通过前序遍历,第一个元素就是树的根节点;
然后在重建左子树,找到左子树的根节点,重建右子树,找到右子树的根节点,递归下去;
中序+后续遍历重建树也是如此;
后续序列的最后一个元素就是树的根节点。

1.2 源代码

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include<stdio.h>
#include<Windows.h>

typedef char ElemType;
typedef struct Node{
ElemType elem;
struct Node *LChild;
struct Node *RChild;
}BiTNode, *BiTree;

// 前序+中序重建二叉树
void ReBuildByPreAndInOrder(char *prelist, char *inlist, int len, BiTree *bt){
if(!prelist || !inlist || len<=0 ) //空树
return;
int i;

// 找到根结点在中序遍历中的位置
for(i = 0; i < len; i++){
if(inlist[i] == prelist[0])
break;
}

if(i>=len)
return;

// 初始化根结点
*bt = (BiTNode*)malloc(sizeof(BiTNode));
if(!bt) // 申请失败
return;
(*bt)->LChild = (*bt)->RChild = NULL;
(*bt)->elem = prelist[0];

// 重建左子树
ReBuildByPreAndInOrder(prelist+1, inlist, i, &(*bt)->LChild);
// 重建右子树
ReBuildByPreAndInOrder(prelist+i+1, inlist+i+1, len-i-1, &(*bt)->RChild);
}

// 中序+后序重建二叉树
void ReBuildByInAndPostOrder(char *inlist,char *postlist, int len, BiTree *bt){
if(!inlist || !postlist || len<=0 ) //空树
return;
int i;

// 找到根结点在中序遍历中的位置
for(i = 0; i < len; i++){
if(inlist[i] == postlist[len-1])
break;
}

if(i>=len)
return;

// 初始化根结点
*bt = (BiTNode*)malloc(sizeof(BiTNode));
if(!bt)
return;
(*bt)->LChild = (*bt)->RChild = NULL;
(*bt)->elem = postlist[len-1];

//重建左子树
ReBuildByInAndPostOrder(inlist, postlist, i, &(*bt)->LChild);
//重建右子树
ReBuildByInAndPostOrder(inlist+i+1, postlist+i, len-i-1, &(*bt)->RChild);
}

void PrintTree(BiTree bt,int nLayer){
int i;
if(bt==NULL)
return;
PrintTree(bt->RChild,nLayer+1);
for(i=0;i<nLayer;i++)
printf(" ");
printf("%c\n", bt->elem);
PrintTree(bt->LChild,nLayer+1);
}

void main(){
char pre[7]={'A', 'B', 'D', 'E', 'C', 'F', 'G'},
inorder1[7] = {'D', 'B', 'E', 'A', 'F', 'C', 'G'},
inorder2[9] = {'G', 'D', 'H', 'B', 'A', 'E', 'C', 'I', 'F'},
post[9] = {'G', 'H', 'D', 'B', 'E', 'I', 'F', 'C', 'A'};
int i=0;

/* 前序+中序重建二叉树 */
printf("Give the preorder and midorder traversal of a binary tree: \nPreorder = ");
for(i=0; i<7; i++){
printf("%c ", pre[i]);
}
printf("\nMidorder = ");
for(i=0; i<7; i++){
printf("%c ", inorder1[i]);
}

BiTree T1=NULL;
ReBuildByPreAndInOrder(pre, inorder1, 7, &T1);
printf("\nThe binary tree constructed by two traversal sequences is: \n");
PrintTree(T1, 1);
/* 前序+中序重建二叉树 */

/* 中序+后序重建二叉树 */
printf("Give the midorder and postorder traversal of a binary tree: \nMidorder = ");
for(i=0; i<9; i++){
printf("%c ", inorder2[i]);
}
printf("\nPostorder = ");
for(i=0; i<9; i++){
printf("%c ", post[i]);
}

BiTree T2=NULL;
ReBuildByInAndPostOrder(inorder2, post, 9, &T2);
printf("\nThe binary tree constructed by two traversal sequences is: \n");
PrintTree(T2, 1);
/* 中序+后序重建二叉树 */

system("pause");
}

1.3 运行情况截图

DS



题目2

1
2
3
求二叉树中值为x的节点所在的层号。
二叉树bt采用二叉链表存储;
设计一个算法level(bt,x)求二叉树中值为x的节点所在的层号

2.1 算法设计思想

在求二叉树深度算法的基础上改进算法;
在含有目标节点的子树上查找,到达目标节点即结束递归

2.2 源代码

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
// 算法1
int layer(BiTree bt, char x){
int cot = 0;
if(bt==NULL)
return cot;
else if(bt->elem==x){
cot = 1;
return cot;
}
else{
// printf("layer(bt->LChild, x): %d\n", layer(bt->LChild, x));
if(layer(bt->LChild, x)){
cot = layer(bt->LChild, x)+1;
return cot;
}
// printf("layer(bt->RChild, x): %d\n", layer(bt->RChild, x));
if(layer(bt->RChild, x)){
cot = layer(bt->RChild, x)+1;
return cot;
}
}
return cot;
}

// 算法2
int find_node_level(BiTree bt, char x, int h){
if (bt == NULL)
return 0;
else if (bt->elem == x)
return h;
else{
int l = find_node_level(bt->LChild, x, h+1);
if (l != 0)
return l;
else
return find_node_level(bt->RChild, x, h+1);
}
}

// 算法3
void level_in_x(BiTree BT,char x,int level){
if (BT == NULL){
return ;
}
if(BT->elem == x){
printf("x in %d",level);
}
level++;
printf("1:%d----\n", level);
level_in_x(BT->LChild,x,level);
printf("2:%d----\n", level);
level_in_x(BT->RChild,x,level);
printf("3:%d----\n", level);
level--;
}

2.3 运行情况截图

DS



题目3

1
2
3
求二叉树的宽度。
利用二叉树层次遍历求二叉树的宽度;
二叉树的宽度即二叉树同层结点数的最大值

3.1 算法设计思想

我利用一个足够大的全局数组来记录遍历过程中的二叉树宽度;
利用一个变量max来记录最大宽度,即为所求;
求宽度的函数依然采用的是先序遍历递归的思想,加一个形参k,对应width数组下标,记录当前深度,来传给子层信息;
如果当前深度k的节点不为空,那么width[k]++,来记录宽度;
max为宽度最大值

3.2 源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define size 100

int width[size];
int max=0;

void MaxWidth(BiTree T,int k){
if(T==NULL)
return;
width[k]++;
if(max<width[k])
max=width[k];
MaxWidth(T->LChild, k+1);
MaxWidth(T->RChild, k+1);
}

3.3 运行情况截图

DS



题目4

1
2
3
4
5
6
7
8
二叉树bt采用二叉链表存储,设计算法实现采用括号表示法输出该二叉树。
A
/ \
B C
/ / \
D E F
\
G A(B(D(,G)),C(E,F))

4.1 算法设计思想

把题目中的括号表示法A(B(D(,G)),C(E,F)),去掉括号变为:
ABDGCEF
这种写法不是我们熟悉的先序遍历吗!
所以我就在二叉树先序遍历算法的基础上改进算法;

a.在节点的左右子树不为空时输出“(”;
b.当节点右子树不为空时输出“,”;
c.在节点的左右子树不为空时输出“)”

4.2 源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
void Brackets(BiTree T){
if (T==NULL)
return;
printf("%c", T->elem);
if(T->LChild!=NULL||T->RChild!=NULL)
printf("( ");
Brackets(T->LChild);
if(T->RChild!=NULL)
printf(", ", T->elem);
Brackets(T->RChild);
if(T->LChild!=NULL||T->RChild!=NULL)
printf(" )");
}

4.3 运行情况截图

DS



题目5

1
2
3
4
求二叉树的路径长度。
二叉树二叉链表存储
二叉树的路径长度即:二叉树中所有结点的路径长度之和。
(结点的路径长度即:从根到结点的分支数)

5.1 算法设计思想

路径长度即为分支数之和;
根据二叉树的性质;
每个节点的头部都有一个分支,除了根节点;
所以分支数之和就是二叉树节点数-1;
那么采用递归的方法求得节点数,就可以求得路劲长度了

5.2 源代码

1
2
3
4
5
6
7
8
9
int Node(BiTree T){
if (T==NULL)
return 0;
else{
return 1 + Node(T->LChild) + Node(T->RChild);
}
}

printf("The path length of this binary tree is: %d\n", Node(T)-1);

5.3 运行情况截图

DS


评论