树和二叉树-遍历
文字描述
二叉樹的先根遍歷
若二叉樹為空,則空操縱,否則
(1) 訪問根結點
(2) 先根遍歷左子樹
(3) 先根遍歷右子樹
二叉樹的中根遍歷
若二叉樹為空,則空操縱,否則
(1) 中根遍歷左子樹
(2) 訪問根結點
(3) 中根遍歷右子樹
二叉樹的后根遍歷
若二叉樹為空,則空操縱,否則
(1) 后根遍歷左子樹
(2) 后根遍歷右子樹
(3) 訪問根結點
二叉樹的層序遍歷
自上到下,自左到右的遍歷
樹的先根遍歷
先訪問樹的根結點,然后依次先根遍歷樹的每顆子樹。
樹的后根遍歷
先依次后根遍歷每顆子樹,然后訪問根結點。
森林的先根遍歷
若森林非空,則:
(1) 訪問森林中第一顆樹的根結點
(2) 先根遍歷第一個樹中根結點的子樹森林
(3) 先根遍歷除第一顆樹之后剩余的樹構成的森林。
森林的中根遍歷
若森林非空,則:
(1) 中根遍歷森林中每一顆樹的根結點的子樹森林。
(2) 訪問第一顆樹的根結點
(3) 中根遍歷除去第一顆樹之后剩余的樹構成的森林。
?
二叉樹遍歷算法的實現
二叉樹遍歷算法有三種:先根遍歷、中根遍歷、后根遍歷; 用函數遞歸的方法很好實現,但是也可以不用函數遞歸,改用借助棧的方法, 具體描述如下:
非遞歸形式的二叉樹的先根遍歷
對于任一結點P:
(1)訪問結點P,并將P入棧
(2)判斷結點P的左孩子是否為空; 2.1)若為空,則取棧頂結點并進行出站并進行出棧操作,并將棧頂結點的右孩子置為當前的結點P; 2.2)若為非空, 則將P的左孩子置為當前的結點P
(3)直到P為NULL并且棧為空,則遍歷結束
非遞歸形式的二叉樹的中根遍歷-方法1
對于任一結點P
(1)若其左孩子不為空,則將P入棧并將P的左孩子置為當前的P,然后對當前結點P再進行相同的處理
(2)若左孩子為空, 則取棧頂元素并進行出棧操縱, 訪問該棧頂元素,然后將棧頂結點的右孩子置為當前的P
(3)直到P為NULL并且棧為空則遍歷結束
非遞歸形式的二叉樹的后根遍歷
要保證根結點在左孩子和右孩子被訪問之后才能訪問,因此對任一結點P,先將其入棧.; 如果P不存在孩子結點, 或者其孩子結點都被訪問過了,則可以直接訪問它; 若非這兩種情況, 則將P的右孩子和左孩子入棧; 這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問, 左孩子和右孩子都在根結點前面被訪問
?非遞歸形式的二叉樹的層序遍歷
對二叉樹進行遍歷的搜索路徑除了上訴按先根、中根或后根外,還可以從上到下、從左至右按層次進行,這種遍歷方法叫二叉樹的層序遍歷,可以借助隊列實現:
(1) 初始時,根結點入隊列
(2) 然后,while循環判斷隊列不為空時,彈出一個結點,訪問它,并把它的所有孩子結點入隊列
示意圖
?
?
圖(1)
二叉樹的先根遍歷 - + a * b – c d / e f
二叉樹的中根遍歷 a + b * c – d – e / f
二叉樹的后根遍歷 a b c d - * + e f / -
?二叉樹的層序遍歷 - + / a * e f b - c d?
圖(2)
樹的先根遍歷 A B C D E
樹的后根遍歷 B D C E A
?
圖(3)
森林的先根遍歷 A B C D E F G H I J
森林的中根遍歷 B C D A F E H J I G
?
算法分析
二叉樹的遍歷,無論哪種次序遍歷,其時間復雜度均為n
所需輔助空間為便利過程中棧的最大深度,而最大深度為樹的深度,即n
?
代碼實現
?
1 #include <stdio.h> 2 #include <stdlib.h> 3 /*測試*/ 4 #define DEBUG 5 /* 6 ./a.out - + a \# \# \* b \# \# - c \# \# d \# \# / e \# \# f \# \# 7 */ 8 #define EQ(a, b) ((a)==(b)) 9 /*樹中結點的最大個數*/ 10 #define MAX_TREE_SIZE 100 11 12 typedef char KeyType; 13 typedef int InfoType; 14 15 /*樹中的結點類型*/ 16 typedef struct{ 17 KeyType key; 18 InfoType otherinfo; 19 }TElemType; 20 21 /* 22 * 二叉樹的鏈式存儲(二叉鏈表) 23 * 24 * 鏈表中的結點包含三個數據:數據域data,左指針域lchild,右指針域rchild 25 */ 26 typedef struct BiTNode{ 27 TElemType data; 28 struct BiTNode *lchild, *rchild; 29 }BiTNode, *BiTree; 30 31 32 /// 33 /////棧的相關結點定義和與非遞歸遍歷算法相關的棧的函數聲明-start//// 34 //棧的存儲空間初始分配量 35 #define STACK_INIT_SIZE 100 36 //棧的存儲空間分配增量 37 #define STACK_INCREMENT 10 38 //棧的結構體表示 39 typedef struct{ 40 //棧底指針 41 BiTNode *base; 42 /*棧頂指針top;插入新元素時,top增1;刪除棧頂元素時,top減1; 43 *非空棧中的棧頂指針始終在棧頂元素的下一個位置上。 44 */ 45 BiTNode *top; 46 //stacksize指示棧的當前可使用的最大容量 47 int stacksize; 48 }SqStack; 49 50 /*構造一個空棧S*/ 51 int InitStack(SqStack *S); 52 53 /*若S為空棧,返回0,否則返回-1*/ 54 int StackEmpty(SqStack *S); 55 56 /*若S不為空,則用e返回S的棧頂元素,并返回0;否則返回-1*/ 57 int GetTop(SqStack *S, BiTNode *e); 58 59 /*插入元素e為新的棧頂元素*/ 60 int Push(SqStack *S, BiTNode *e); 61 62 /*若棧不為空,則刪除S的棧頂元素,用e返回其值,返回0;否則返回-1*/ 63 int Pop(SqStack *S, BiTNode *e); 64 /// 65 /// 66 67 68 /* 69 * 按先根次序輸入二叉樹中結點的值,'#'表示空結點 70 * 構造二叉鏈表表示的二叉樹T 71 */ 72 int I = 0; 73 BiTree CreateBiTree(TElemType input[]){ 74 TElemType data = input[I++]; 75 BiTree T = NULL; 76 if(data.key == '#'){ 77 T = NULL; 78 return T; 79 }else{ 80 if(!(T=(BiTNode *)malloc(sizeof(BiTNode)))){ 81 printf("Error: overflow!\n"); 82 exit(1); 83 } 84 T->data = data; 85 T->lchild = CreateBiTree(input); 86 T->rchild = CreateBiTree(input); 87 return T; 88 } 89 } 90 91 int vist(TElemType e){ 92 printf("%c ", e.key); 93 return 0; 94 } 95 96 /*遞歸形式的二叉樹的先根遍歷算法*/ 97 int PreOrderTraverse(BiTree T, int(*fun)(TElemType e)){ 98 if(T){ 99 fun(T->data); 100 PreOrderTraverse(T->lchild, fun); 101 PreOrderTraverse(T->rchild, fun); 102 return 0; 103 }else{ 104 return 0; 105 } 106 } 107 108 /*遞歸形式的二叉樹的中根遍歷算法*/ 109 int InOrderTraverse(BiTree T, int (*fun)(TElemType e)){ 110 if(T){ 111 InOrderTraverse(T->lchild, fun); 112 fun(T->data); 113 InOrderTraverse(T->rchild, fun); 114 return 0; 115 }else{ 116 return 0; 117 } 118 } 119 120 /*遞歸形式的二叉樹的后根遍歷算法*/ 121 int PostOrderTraverse(BiTree T, int (*fun)(TElemType e)){ 122 if(T){ 123 PostOrderTraverse(T->lchild, fun); 124 PostOrderTraverse(T->rchild, fun); 125 fun(T->data); 126 return 0; 127 }else{ 128 return 0; 129 } 130 } 131 132 /* 133 *非遞歸形式的二叉樹的先根遍歷 134 * 135 *對于任一結點P 136 *(1)訪問結點P,并將P入棧 137 *(2)判斷結點P的左孩子是否為空 138 * 2.1 若為空,則取棧頂結點并進行出站并進行出棧操作,并將棧頂結點的右孩子置為當前的結點P 139 * 2.2 若為非空, 則將P的左孩子置為當前的結點P 140 *(3) 直到P為NULL并且棧為空,則遍歷結束 141 */ 142 int PreOrderTraverse_NonRecur(BiTree T, int (*fun)(TElemType e)){ 143 SqStack S; 144 if(InitStack(&S)<0){ 145 return -1; 146 } 147 BiTNode *p = T, q; 148 while(p || StackEmpty(&S)){ 149 if(p){ 150 fun(p->data); 151 Push(&S, p); 152 p = p->lchild; 153 }else{ 154 Pop(&S, &q); 155 p = q.rchild; 156 } 157 } 158 } 159 160 /* 161 *非遞歸形式的二叉樹的中根遍歷-方法1 162 * 163 *對于任一結點P 164 *(1)若其左孩子不為空,則將P入棧并將P的左孩子置為當前的P,然后對當前結點P再進行相同的處理 165 *(2)若左孩子為空, 則取棧頂元素并進行出棧操縱, 訪問該棧頂元素,然后將棧頂結點的右孩子置為當前的P 166 *(3)直到P為NULL并且棧為空則遍歷結束 167 */ 168 int InOrderTraverse_NonRecur(BiTree T, int (*fun)(TElemType e)){ 169 SqStack S; 170 if(InitStack(&S)<0){ 171 return -1; 172 } 173 Push(&S, T); 174 BiTNode *p; 175 176 while(StackEmpty(&S)<0){ 177 while((!GetTop(&S, p)) && p && !Push(&S, p->lchild)); 178 Pop(&S, p); 179 fun(p->data); 180 if(StackEmpty(&S)){ 181 Pop(&S, p); 182 fun(p->data); 183 Push(&S,p->rchild); 184 } 185 } 186 return 0; 187 } 188 189 /*非遞歸形式的二叉樹的中根遍歷-方法2*/ 190 int InOrderTraverse_NonRecur2(BiTree T, int (*fun)(TElemType e)){ 191 SqStack S; 192 if(InitStack(&S)<0){ 193 return -1; 194 } 195 BiTNode *p = T, q; 196 while(p || StackEmpty(&S)){ 197 if(p){ 198 Push(&S, p); 199 p = p->lchild; 200 }else{ 201 Pop(&S, &q); 202 fun(q.data); 203 p = q.rchild; 204 } 205 } 206 } 207 208 /*比較兩個結點是否相等,主要用于非遞歸后序遍歷算法中判斷兩個結點是否為同一個結點*/ 209 int compare(BiTNode *node1, BiTNode *node2) 210 { 211 if(node1 == NULL|| node2 == NULL){ 212 return -1; 213 }else if((node1->data.key == node2->data.key) && (node1->data.otherinfo == node2->data.otherinfo)){ 214 return 0; 215 }else{ 216 return -1; 217 } 218 } 219 220 /* 221 *非遞歸形式的二叉樹的后根遍歷 222 * 223 *要保證根結點在左孩子和右孩子被訪問之后才能訪問,因此對任一結點P,先將其入棧. 224 *如果P不存在孩子結點, 或者其孩子結點都被訪問過了,則可以直接訪問它; 225 *若非這兩種情況, 則將P的右孩子和左孩子入棧; 226 *這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問, 左孩子和右孩子都在根結點前面被訪問 227 */ 228 int PostOrderTraverse_NonRecur(BiTree T, int (*fun)(TElemType e)){ 229 SqStack S; 230 if(InitStack(&S)<0){ 231 return -1; 232 } 233 //當前結點 234 BiTNode *curr = (BiTNode*)malloc(sizeof(BiTNode)); 235 //前一次被訪問過的結點 236 BiTNode pre = {'0', -1}; 237 238 Push(&S, T); 239 while(StackEmpty(&S)){ 240 GetTop(&S, curr); 241 if((curr->lchild == NULL && curr->rchild == NULL) 242 || (!compare(curr->lchild, &pre)|| !compare(curr->rchild, &pre))){ 243 //如果當前結點沒有孩子結點或者該結點的孩子結點都被訪問過 244 fun(curr->data); 245 pre = *curr; 246 Pop(&S, curr); 247 }else{ 248 //右孩子入棧 249 Push(&S, curr->rchild); 250 //左孩子入棧 251 Push(&S, curr->lchild); 252 } 253 } 254 255 return 0; 256 } 257 258 259 int main(int argc, char *argv[]) 260 { 261 if(argc < 2) 262 return -1; 263 264 TElemType input[MAX_TREE_SIZE]; 265 int i = 0, j = 0; 266 for(i=0; i<MAX_TREE_SIZE; i++){ 267 input[i].key = '#'; 268 } 269 270 //按先根次序輸入二叉樹中結點的值,'-'表示空樹 271 for(i=1; i<argc; i++){ 272 if(i>MAX_TREE_SIZE) 273 break; 274 input[i-1].key = argv[i][0]; 275 input[i-1].otherinfo = i-1; 276 } 277 #ifdef DEBUG 278 printf("按先根順序建立二叉樹(#表示空結點):\n"); 279 for(j=0; j< i-1; j++){ 280 printf("%c ", input[j].key); 281 } 282 printf("\n"); 283 #endif 284 BiTree T = CreateBiTree(input); 285 286 printf("遞歸形式的二叉樹的先根遍歷算法\n"); 287 PreOrderTraverse(T, vist); 288 289 printf("\n遞歸形式的二叉樹的中根遍歷算法\n"); 290 InOrderTraverse(T, vist); 291 292 printf("\n遞歸形式的二叉樹的后根遍歷算法\n"); 293 PostOrderTraverse(T, vist); 294 295 printf("\n非遞歸形式的二叉樹的先根遍歷\n"); 296 PreOrderTraverse_NonRecur(T,vist); 297 298 printf("\n非遞歸形式的二叉樹的中根遍歷-方法1\n"); 299 InOrderTraverse_NonRecur(T,vist); 300 301 printf("\n非遞歸形式的二叉樹的中根遍歷-方法2\n"); 302 InOrderTraverse_NonRecur2(T,vist); 303 304 printf("\n非遞歸形式的二叉樹的后根遍歷\n"); 305 PostOrderTraverse_NonRecur(T,vist); 306 printf("\n"); 307 return 0; 308 } 309 310 311 312 / 313 /////與非遞歸遍歷算法相關的棧的函數實現-start//// 314 /*構造一個空棧S*/ 315 int InitStack(SqStack *S) 316 { 317 S->base = (BiTNode *)malloc(STACK_INIT_SIZE * sizeof(BiTNode)); 318 if(!S->base){ 319 return -1; 320 } 321 S->top = S->base; 322 S->stacksize = STACK_INIT_SIZE; 323 return 0; 324 } 325 326 /*若S為空棧,返回0,否則返回-1*/ 327 int StackEmpty(SqStack *S) 328 { 329 if(S->top == S->base){ 330 return 0; 331 }else{ 332 return -1; 333 } 334 } 335 336 /*若S不為空,則用e返回S的棧頂元素,并返回0;否則返回-1*/ 337 int GetTop(SqStack *S, BiTNode *e) 338 { 339 if(S->top == S->base){ 340 return -1; 341 }else{ 342 if((S->top-1) == NULL){ 343 e = NULL; 344 }else{ 345 *e = *(S->top-1); 346 } 347 return 0; 348 } 349 } 350 351 352 /*插入元素e為新的棧頂元素*/ 353 int Push(SqStack *S, BiTNode *e) 354 { 355 //棧滿,需要追加存儲空間 356 if((S->top-S->base) >= S->stacksize){ 357 S->base = (BiTNode *)realloc(S->base, (S->stacksize+STACK_INCREMENT) * sizeof(BiTNode)); 358 if(!S->base){ 359 return -1; 360 } 361 S->top = S->base + S->stacksize; 362 S->stacksize += STACK_INCREMENT; 363 } 364 if(e == NULL){ 365 return -1; 366 }else{ 367 *S->top = *e; 368 } 369 S->top += 1; 370 return 0; 371 } 372 373 374 /*若棧不為空,則刪除S的棧頂元素,用e返回其值,返回0;否則返回-1*/ 375 int Pop(SqStack *S, BiTNode *e) 376 { 377 if(S->top == S->base){ 378 return -1; 379 }else{ 380 S->top -= 1; 381 *e = *(S->top); 382 return 0; 383 } 384 } 385 386 / 387 / 二叉樹的遍歷(遞歸和非遞歸)?
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define DEBUG 5 #define EQ(a, b) ((a)==(b)) 6 /*樹中結點的最大個數*/ 7 #define MAX_TREE_SIZE 100 8 9 typedef char KeyType; 10 typedef int InfoType; 11 12 /*樹中的結點類型*/ 13 typedef struct{ 14 KeyType key; 15 InfoType otherinfo; 16 }TElemType; 17 18 /* 19 * 二叉樹的鏈式存儲(二叉鏈表) 20 * 21 * 鏈表中的結點包含三個數據:數據域data,左指針域lchild,右指針域rchild 22 */ 23 typedef struct BiTNode{ 24 TElemType data; 25 struct BiTNode *lchild, *rchild; 26 }BiTNode, *BiTree; 27 28 //// 29 //與隊列相關的結構體和函數聲明 30 typedef struct QNode{ 31 BiTNode data; 32 struct QNode *next; 33 }QNode, *QuenePtr; 34 35 typedef struct{ 36 QuenePtr front; 37 QuenePtr rear; 38 }LinkQueue; 39 40 LinkQueue* InitQueue(void); 41 int QueueEmpty(LinkQueue *Q); 42 int GetHead(LinkQueue *Q, BiTNode *e); 43 int EnQueue(LinkQueue *Q, BiTNode *e); 44 int DeQueue(LinkQueue *Q, BiTNode *e); 45 //// 46 47 /* 48 * 建立二叉鏈表 49 * 50 * 按先根次序輸入二叉樹中結點的值,'#'表示空結點 51 */ 52 int I = 0; 53 BiTree CreateBiTree(TElemType input[]){ 54 TElemType data = input[I++]; 55 BiTree T = NULL; 56 if(data.key == '#'){ 57 T = NULL; 58 return T; 59 }else{ 60 if(!(T=(BiTNode *)malloc(sizeof(BiTNode)))){ 61 printf("Error: overflow!\n"); 62 exit(1); 63 } 64 T->data = data; 65 T->lchild = CreateBiTree(input); 66 T->rchild = CreateBiTree(input); 67 return T; 68 } 69 } 70 71 int vist(TElemType e){ 72 printf("%c ", e.key); 73 return 0; 74 } 75 76 /* 77 * 非遞歸形式的二叉樹的層序遍歷 78 * 79 * 從上到下,從左到右按層次遍歷。 80 * (1) 初始時,根結點入隊列 81 * (2) 然后,while循環判斷隊列不為空時,彈出一個結點,訪問它,并把它的所有孩子結點入隊列 82 */ 83 int LevelOrderTraverse_NonRecur(BiTree T, int (*fun)(TElemType e)){ 84 LinkQueue *Q = InitQueue(); 85 if(!Q){ 86 return -1; 87 } 88 EnQueue(Q, T); 89 BiTNode node; 90 while(QueueEmpty(Q)){ 91 //刪除最前面的結點 92 DeQueue(Q, &node); 93 fun(node.data); 94 //判斷最前面的左孩子結點是否為空,不是就放入隊列 95 if(node.lchild){ 96 EnQueue(Q, node.lchild); 97 } 98 //判斷最前面的右孩子結點是否為空,不是就放入隊列 99 if(node.rchild){ 100 EnQueue(Q, node.rchild); 101 } 102 } 103 return 0; 104 } 105 106 int main(int argc, char *argv[]) 107 { 108 if(argc < 2) 109 return -1; 110 TElemType input[MAX_TREE_SIZE]; 111 int i = 0, j = 0; 112 for(i=0; i<MAX_TREE_SIZE; i++){ 113 input[i].key = '#'; 114 } 115 116 //按先根次序輸入二叉樹中結點的值,'#'表示空樹 117 for(i=1; i<argc; i++){ 118 if(i>MAX_TREE_SIZE) 119 break; 120 input[i-1].key = argv[i][0]; 121 input[i-1].otherinfo = i-1; 122 } 123 #ifdef DEBUG 124 printf("按先根順序建立二叉樹(#表示空結點):\n"); 125 for(j=0; j< i-1; j++){ 126 printf("%c ", input[j].key); 127 } 128 printf("\n"); 129 #endif 130 BiTree T = CreateBiTree(input); 131 printf("非遞歸形式的二叉樹的層序遍歷\n"); 132 LevelOrderTraverse_NonRecur(T, vist); 133 printf("\n"); 134 return 0; 135 } 136 137 //// 138 //與隊列相關的函數的實現 139 LinkQueue* InitQueue(void) 140 { 141 LinkQueue *Q = (LinkQueue*)malloc(sizeof(LinkQueue)); 142 Q->front = Q->rear = (QuenePtr)malloc(sizeof(QNode)); 143 if(!Q->front){ 144 printf("malloc fail!\n"); 145 return NULL; 146 } 147 return Q; 148 } 149 150 int QueueEmpty(LinkQueue *Q) 151 { 152 if(Q->front == Q->rear){ 153 return 0; 154 }else{ 155 return -1; 156 } 157 } 158 159 int GetHead(LinkQueue *Q, BiTNode *e) 160 { 161 if(Q->front == Q->rear){ 162 return -1; 163 } 164 *e = Q->front->next->data; 165 return 0; 166 } 167 168 int EnQueue(LinkQueue *Q, BiTNode *e) 169 { 170 QuenePtr p = (QuenePtr)malloc(sizeof(QNode)); 171 if(!p){ 172 printf("malloc fail!\n"); 173 return -1; 174 } 175 p->data = *e; 176 p->next = NULL; 177 Q->rear->next = p; 178 Q->rear = p; 179 return 0; 180 } 181 182 int DeQueue(LinkQueue *Q, BiTNode *e) 183 { 184 if(Q->front == Q->rear){ 185 return -1; 186 } 187 QuenePtr p = Q->front->next; 188 *e = p->data; 189 Q->front->next = p->next; 190 if(p == Q->rear){ 191 Q->rear = Q->front; 192 } 193 free(p); 194 return 0; 195 } 196 //// 二叉樹的層序遍歷?
運行
?
?
轉載于:https://www.cnblogs.com/aimmiao/p/9438776.html
總結
- 上一篇: mac 开关机
- 下一篇: 手眼标定eye-to-hand 示例:h