夏天看机器学习之余,把C语言给过了一遍,现在开始数据结构的学习了。最近看的二叉树,照着书实现了一下。

其中包括二叉树的一些基本操作:初始化,建立,销毁,判空,深度和几种遍历。因为书上没给出非递归的遍历的非递归形式,自己这边给总结一下。代码本来是用C写的,但是其中有些功能的实现需要用到队列或者栈,直接调用C++的STL了。如下是相关代码。

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <queue>
#include <stack>
using namespace std;
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */
typedef int Status;
typedef char TElemType;
TElemType Nil = ' ';
/* 用于构造二叉树********************************** */
int index=1;
typedef char String[24]; /* 0号单元存放串的长度 */
String str;
Status StrAssign(String T,char *chars)
{
int i;
if(strlen(chars)>MAXSIZE)
return ERROR;
else
{
T[0]=strlen(chars);
for(i=1;i<=T[0];i++)
T[i]=*(chars+i-1);
return OK;
}
}
/* ************************************************ */
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
Status InitBiTree(BiTree *T);
void CreateBiTree(BiTree *T);
void DestroyBiTree(BiTree *T);
Status BiTreeEmpty(BiTree T);
TElemType Root(BiTree T);
TElemType Value(BiTree p);
void visit(BiTree T);
int BiTreeDepth(BiTree T);
int BiTreeDepthNonRecursion(BiTree T);
int BiTreeDepthNonRecursion2(BiTree T);
void PreOrderTraverse(BiTree T);
void PreOrderNonRecursion(BiTree T);
void InOrderTraverse(BiTree T);
void InOrderNonRecursion(BiTree T);
void PostOrderTraverse(BiTree T);
void PostOrderNonRecurion(BiTree T);
void LevelOrderTraverse(BiTree T);
void PrintLastInEachLevel(BiTree T);
void PrintLevelOrderByLevel(BiTree T);
int main()
{
int i;
BiTree T;
TElemType e1;
InitBiTree(&T);
//StrAssign(str,"ABDH#K###E##CFI###G#J##");
CreateBiTree(&T);
printf("构造空二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepthNonRecursion2(T));
e1=Root(T);
printf("二叉树的根为: %c\n",e1);
printf("\n前序遍历二叉树:\n");
PreOrderTraverse(T);
//PreOrderNonRecursion(T);
printf("\n中序遍历二叉树:\n");
InOrderTraverse(T);
//InOrderNonRecursion(T);
printf("\n后序遍历二叉树:\n");
PostOrderTraverse(T);
//PostOrderNonRecurion(T);
printf("\n层次遍历二叉树:\n");
//LevelOrderTraverse(T);
PrintLevelOrderByLevel(T);
printf("\n输出每层的最后一个结点:\n");
PrintLastInEachLevel(T);
DestroyBiTree(&T);
printf("\n清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T));
i=Root(T);
if(!i)
printf("树空,无根\n");
getchar();
getchar();
return 0;
}
//* 构造空二叉树T */
Status InitBiTree(BiTree *T)
{
*T = NULL;
return OK;
}
// 按前序输入二叉树中结点的值(一个字符)
// #表示空树,构造二叉链表表示二叉树T。
void CreateBiTree(BiTree *T)
{
TElemType ch;
scanf("%c", &ch);
if (ch == '#')
(*T) = NULL;
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
if (!*T)
exit(OVERFLOW);
(*T)->data = ch;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}
// 初始条件: 二叉树T存在。操作结果: 销毁二叉树T
void DestroyBiTree(BiTree *T)
{
if (*T)
{
if ((*T)->lchild)
DestroyBiTree(&(*T)->lchild);
if ((*T)->rchild)
DestroyBiTree(&(*T)->rchild);
free(*T);
*T = NULL;
}
}
// 初始条件:二叉树存在
// 操作结果:若T为空,则返回TRUE;否则返回FALSE
Status BiTreeEmpty(BiTree T)
{
if (!T)
return TRUE;
else
return FALSE;
}
// 初始条件:二叉树存在
// 操作结果:返回T的根
TElemType Root(BiTree T)
{
if (!T)
return Nil;
else
return T->data;
}
// 初始条件:节点存在
// 操作结果:输出结点的数据域
void visit(BiTNode *p)
{
if (p)
printf("%c ", p->data);
}
// 初始条件:二叉树存在
// 操作结果:返回二叉树深度
// 递归实现
int BiTreeDepth(BiTree T)
{
if (!T)
return 0;
int i, j;
if (T->lchild)
i = BiTreeDepth(T->lchild); // 递归求出左子树高度
else
i = 0;
if (T->rchild)
j = BiTreeDepth(T->rchild); // 递归求出右子树高度
else
j = 0;
return i > j ? i+1 : j+1;
}
// 求二叉树高度的非递归形式
int BiTreeDepthNonRecursion(BiTree T)
{
if (!T)
return 0;
queue<BiTNode *> Q; // 借助队列实现层次遍历,从而求出高度
BiTNode *p; // 记录队列头部
BiTNode *back; // 记录队列尾部指针
int level = 0; // 队列高度
Q.push(T);
back = Q.back();
while (!Q.empty())
{
p = Q.front();
Q.pop();
if (p->lchild)
Q.push(p->lchild);
if (p->rchild)
Q.push(p->rchild);
if (p == back)
{
level++;
if (!Q.empty()) // 防止最后Q为空时出错
back = Q.back();
}
}
return level;
}
// 求二叉树高度的非递归形式
int BiTreeDepthNonRecursion2(BiTree T)
{
BiTNode *Q[MAXSIZE]; // 借助队列实现层次遍历,从而求出高度。此时用数组实现队列
int level = 0; // 二叉树高度
int last = 0; // 每层次最后一个结点
int front = -1; // 队列头指针
int rear = -1; // 队列尾指针
BiTNode *p;
Q[++rear] = T;
last = rear;
while (front < rear) // 队列不空
{
p = Q[++front];
if (p->lchild)
Q[++rear] = p->lchild;
if (p->rchild)
Q[++rear] = p->rchild;
if (front == last)
{
level++;
if (front < rear)
last = rear;
}
}
return level;
}
// 初始条件:二叉树存在
// 操作结果:前序遍历二叉树
void PreOrderTraverse(BiTree T)
{
if (!T)
return;
visit(T);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
// 前序遍历非递归形式
void PreOrderNonRecursion(BiTree T)
{
if (!T)
return;
stack<BiTNode *> S; // 借助栈实现非递归遍历
BiTNode *p;
p = T;
while (p || !S.empty())
{
while (p)
{
S.push(p);
visit(p); // 在每次入栈时进行访问
p = p->lchild;
}
if (!S.empty())
{
p = S.top();
S.pop();
p = p->rchild;
}
}
}
// 初始条件:二叉树存在
// 操作结果:中序遍历二叉树
void InOrderTraverse(BiTree T)
{
if (!T)
return;
InOrderTraverse(T->lchild);
visit(T);
InOrderTraverse(T->rchild);
}
// 中序遍历二叉树非递归形式
void InOrderNonRecursion(BiTree T)
{
if (!T)
return;
stack<BiTNode *> S;
BiTNode *p;
p = T;
while (p || !S.empty())
{
while (p)
{
S.push(p);
p = p->lchild;
}
if (!S.empty())
{
p = S.top();
S.pop();
visit(p); // 每次从栈中弹出的时候访问结点
p = p->rchild;
}
}
}
// 初始条件:二叉树存在
// 操作结果:后序递归遍历二叉树
void PostOrderTraverse(BiTree T)
{
if (!T)
return;
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
visit(T);
}
// 后序遍历非递归形式
// 难点是分清栈中弹出根结点时,是从左子树弹出还是右子树弹出。所以使用辅助指针r。
void PostOrderNonRecurion(BiTree T)
{
if (!T)
return;
stack<BiTNode *> S;
BiTNode *p;
BiTNode *r; // 用指针r记录最近访问的结点
p = T;
r = NULL;
while (p || !S.empty())
{
while (p)
{
S.push(p);
p = p->lchild;
}
if (!S.empty())
{
p = S.top();
if (p->rchild && p->rchild != r) // 如果右子树存在,且未访问过
{
p = p->rchild;
S.push(p);
p = p->lchild;
}
else
{
S.pop();
visit(p);
r = p;
p = NULL;
}
}
}
}
// 初始条件:二叉树存在
// 操作结果:层次遍历二叉树
void LevelOrderTraverse(BiTree T)
{
if (!T)
return;
queue<BiTNode *> Q; // 借助队列实现层次遍历
BiTNode *p;
Q.push(T);
while (!Q.empty())
{
p = Q.front();
Q.pop();
visit(p); // 每次弹出的时候访问结点
if (p->lchild)
Q.push(p->lchild);
if (p->rchild)
Q.push(p->rchild);
}
}
// 初始条件:二叉树存在
// 操作结果:访问每层二叉树最右边的结点
void PrintLastInEachLevel(BiTree T)
{
if (!T) // 如果树为空,则返回
return;
queue<BiTNode *> Q;
BiTNode *p;
BiTNode *back; // 指向每层最后一个结点的指针
Q.push(T);
back = Q.back();
while (!Q.empty())
{
p = Q.front();
Q.pop();
if (p->lchild)
Q.push(p->lchild);
if (p->rchild)
Q.push(p->rchild);
if (p == back)
{
visit(p);
if (!Q.empty())
back = Q.back();
}
}
}
// 初始条件:二叉树存在
// 操作结果:分行输出每层二叉树的结点
void PrintLevelOrderByLevel(BiTree T)
{
if (!T)
return;
queue<BiTNode *> Q;
BiTNode *p;
BiTNode *back; // 记录每层最右边的结点,从而实现分行输出
Q.push(T);
back = Q.back();
while (!Q.empty())
{
p = Q.front();
Q.pop();
visit(p);
if (p->lchild)
Q.push(p->lchild);
if (p->rchild)
Q.push(p->rchild);
if (p == back)
{
putchar('\n');
if (!Q.empty())
back = Q.back();
}
}
}

本身感觉现在这些在计算机专业里面应该是太基础的东西了,不想贴出来的,但是确实这个算是一个里程碑吧——感觉自己对编程有点入门了。下一篇会把用类实现的二叉树的代码贴上来,之后再写点自学编程上面的一些感悟或者说一些经验吧。

参考资料:

1.《大话数据结构》