1. 程式人生 > >二叉樹 - 遍歷和存儲結構

二叉樹 - 遍歷和存儲結構

前序遍歷 main inorder esp bottom ive align return c 編程

在《二叉樹的定義和性質》中我們已經認識了二叉樹這種數據結構。我們知道鏈表的每個節點可以有一個後繼,而二叉樹(Binary Tree)的每個節點可以有兩個後繼。比如這樣定義二叉樹的節點:

typedef struct node *link;

struct node {

unsigned char item;

link l, r;

};

這樣的節點可以組織成下圖所示的形態。

技術分享圖片

二叉樹可以這樣遞歸地定義:
1. 就像鏈表有頭指針一樣,每個二叉樹都有一個根指針(上圖中的root指針)指向它。根指針可以是NULL,表示空二叉樹,或者
2. 根指針可以指向一個節點,這個節點除了有數據成員之外還有兩個指針域,這兩個指針域又分別是另外兩個二叉樹(左子樹和右子樹)的根指針。


鏈表的遍歷方法是顯而易見的:從前到後遍歷即可。二叉樹是一種樹狀結構,如何做到把所有節點都走一遍不重不漏呢?有以下幾種方法,如下圖(來自《linux c 編程一站式學習》)所示:

技術分享圖片

前序(Pre-order Traversal)(深度優先搜索)、中序(In-order Traversal)、後序遍歷(Post-order Traversal)、層序遍歷(Level-order Traversal)(廣度優先搜索)。如何分辨三種次序的遍歷方法呢?《data structrue and algorithm analysis in c》中有一句:We can evaluate an expression tree, T, by applying the operator at the root to the values obtained by recursively evaluating the left and right subtrees.

個人總結就是:前序 (root->left->right) ; 中序(left->root->right); 後序(left->right->root)

舉例上圖來說,前序遍歷,首先root是4,接著要Left,就是指左邊子樹,在左邊子樹中又先是root即2,然後是left的1,接著說right的3,現在左邊子樹遞歸完畢了,接著右邊子樹,同樣先root即5,沒有left,最後是right的6,所以最後排列是421356。

註意:已知前序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹。

已知後序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹。

但已知前序和後序遍歷序列,是不能確定一棵二叉樹的。


如果我們要在內存中建立一個如圖6-9-1左圖這樣的樹,為了能讓每個結點確認是否有左右孩子,可以對它進行擴展,如右圖那樣,也就是將二叉樹的每個結點的空指針引出一個虛結點,其值為一特定值,比如‘#‘。我們稱這種處理後的二叉樹為擴展二叉樹。擴展二叉樹就可以做到一個遍歷序列確定一棵二叉樹了。比如圖6-9-1的前序遍歷序列就為AB#D##C##。

技術分享圖片


示例程序如下:(改變自《大話數據結構》)

C++ Code
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

#include<iostream>
using namespace std;

#define MAXSIZE 50

typedef char ElemType;
typedef char String[MAXSIZE + 1]; //以‘\0’結尾
String str; /* 用於構造二叉樹*/
ElemType NoChar = ‘ ‘; /* 字符型以空格符為空 */

/* 結點結構 */
typedef struct BTNode
{
ElemType data;/* 結點數據 */
struct BTNode *LChild;/* 左右孩子指針 */
struct BTNode *RChild;
} BTNode, *BTNodePtr;

/* 構造一個字符串 */
bool StrAssign(String Dest, char *ptr)
{
cout << "Assign Str ..." << endl;
int i;
for (i = 0; ptr[i] != ‘\0‘ && i < MAXSIZE; i++)
Dest[i] = ptr[i];
Dest[i] = ‘\0‘;
return true;
}
/* 構造空二叉樹 */
bool InitBTree(BTNodePtr *Tpp)
{
*Tpp = NULL;
return true;
}
/* 銷毀二叉樹 */
void DestroyBTree(BTNodePtr *Tpp)
{
if (*Tpp)
{
if ((*Tpp)->LChild)/* 有左孩子 */
DestroyBTree(&(*Tpp)->LChild);/* 銷毀左孩子子樹 */
if ((*Tpp)->RChild)/* 有右孩子 */
DestroyBTree(&(*Tpp)->RChild); /* 銷毀右孩子子樹 */
free(*Tpp);/* 釋放根結點 */
*Tpp = NULL;/* 空指針賦0 */
}
}
/* 按前序輸入二叉樹中結點的值(一個字符) */
/* #表示空樹,構造二叉鏈表表示二叉樹。 */
void CreateBTree(BTNodePtr *Tpp)
{
ElemType ch;
static int i = 0;
if (str[i] != ‘\0‘)
ch = str[i++];
if (ch == ‘#‘)
*Tpp = NULL;
else
{
*Tpp = (BTNodePtr)malloc(sizeof(BTNode));
if (!*Tpp)
exit(1);
(*Tpp)->data = ch;/* 生成根結點 */
CreateBTree(&(*Tpp)->LChild);/* 構造左子樹 */
CreateBTree(&(*Tpp)->RChild);/* 構造右子樹 */
}
}

bool BTreeEmpty(BTNodePtr Tp)
{
if (Tp)
return false;
else
return true;
}
/*返回二叉樹的深度 */
int BTreeDepth(BTNodePtr Tp)
{
int i, j;
if (!Tp)
return 0;
if (Tp->LChild)
i = BTreeDepth(Tp->LChild);
else
i = 0;
if (Tp->RChild)
j = BTreeDepth(Tp->RChild);
else
j = 0;
return i > j ? i + 1 : j + 1;
}
/* 返回根節點的數值 */
ElemType Root(BTNodePtr Tp)
{
if (BTreeEmpty(Tp))
return NoChar;
else
return Tp->data;
}
/* 前序遞歸遍歷*/
void PreOrderTraverse(BTNodePtr Tp)
{
if (Tp == NULL)
return;
cout << Tp->data << ‘ ‘;
PreOrderTraverse(Tp->LChild);
PreOrderTraverse(Tp->RChild);
}
/* 中序遞歸遍歷*/
void InOrderTraverse(BTNodePtr Tp)
{
if (Tp == NULL)
return;
InOrderTraverse(Tp->LChild);
cout << Tp->data << ‘ ‘;
InOrderTraverse(Tp->RChild);

}
/* 後序遞歸遍歷*/
void PostOrderTraverse(BTNodePtr Tp)
{
if (Tp == NULL)
return;
PostOrderTraverse(Tp->LChild);
PostOrderTraverse(Tp->RChild);
cout << Tp->data << ‘ ‘;
}

int main(void)
{
BTNodePtr Tp;
InitBTree(&Tp);
StrAssign(str, "ABDH#K###E##CFI###G#J##");
cout << "輸入字符序列(前序遍歷)為:" << endl;
cout << str << endl;
CreateBTree(&Tp);

cout << "前序遍歷二叉樹:" << endl;
PreOrderTraverse(Tp);
cout << endl;
cout << "中序遍歷二叉樹:" << endl;
InOrderTraverse(Tp);
cout << endl;
cout << "後序遍歷二叉樹:" << endl;
PostOrderTraverse(Tp);
cout << endl;

cout << "二叉樹的根節點為:" << Root(Tp) << endl;
cout << "二叉樹的深度為:" << BTreeDepth(Tp) << endl;

cout << "銷毀二叉樹 ..." << endl;
DestroyBTree(&Tp);
if (BTreeEmpty(Tp))
cout << "二叉樹現已為空..." << endl << endl;

return 0;
}







輸出為:

技術分享圖片


二叉樹 - 遍歷和存儲結構