二叉樹的遍歷不用棧和遞歸
轉自:ACM之家?http://www.acmerblog.com/inorder-tree-traversal-without-recursion-and-without-stack-5988.html
我們知道,在深度搜索遍歷的過程中,之所以要用遞歸或者是用非遞歸的棧方式,參考二叉樹非遞歸中序遍歷,都是因為其他的方式沒法記錄當前節點的parent,而如果在每個節點的結構里面加個parent 分量顯然是不現實的,那么Morris是怎么解決這一問題的呢?好吧,他用得很巧妙,實際上是用葉子節點的空指針來記錄當前節點的位置,然后一旦遍歷到了葉子節點,發現葉子節點的右指針指向的是當前節點,那么就認為以當前節點的左子樹已經遍歷完成。Morris 遍歷正是利用了線索二叉樹?的思想。
以inorder為例,初始化當前節點為root,它的遍歷規則如下:
- 如果當前節點為空,程序退出。
- 如果當前節點非空,
- 如果當前節點的左兒子為空,那么輸出當前節點,當前節點重置為當前節點的右兒子。
- 如果當前節點的左兒子非空,找到當前節點左子樹的最右葉子節點(此時最右節點的右兒子有兩種情況,一種是指向當前節點,一種是為空,你也許感到奇怪,右節點的右兒子怎么可能非空,注意,這里的最右葉子節點只帶的是原樹中的最右葉子節點。),若其最右葉子節點為空,令其指向當前節點,將當前節點重置為其左兒子,若其最右節點指向當前節點,輸出當前節點,將當前節點重置為當前節點的右兒子,并恢復樹結構,即將最右節點的右節點再次設置為NULL
1 #include<stdio.h> 2 #include<stdlib.h> 3 4 struct tNode 5 { 6 int data; 7 struct tNode* left; 8 struct tNode* right; 9 }; 10 11 void MorrisTraversal(struct tNode *root) 12 { 13 struct tNode *current,*pre; 14 15 if(root == NULL) 16 return; 17 18 current = root; 19 while(current != NULL) 20 { 21 if(current->left == NULL) 22 { 23 printf(" %d ", current->data); 24 current = current->right; 25 } 26 else 27 { 28 /* 找到current的前驅節點 */ 29 pre = current->left; 30 while(pre->right != NULL && pre->right != current) 31 pre = pre->right; 32 33 /* 將current節點作為其前驅節點的右孩子 */ 34 if(pre->right == NULL) 35 { 36 pre->right = current; 37 current = current->left; 38 } 39 40 /* 恢復樹的原有結構,更改right 指針 */ 41 else 42 { 43 pre->right = NULL; 44 printf(" %d ",current->data); 45 current = current->right; 46 } /* End of if condition pre->right == NULL */ 47 } /* End of if condition current->left == NULL*/ 48 } /* End of while */ 49 } 50 51 struct tNode* newtNode(int data) 52 { 53 struct tNode* tNode = (struct tNode*) 54 malloc(sizeof(struct tNode)); 55 tNode->data = data; 56 tNode->left = NULL; 57 tNode->right = NULL; 58 59 return(tNode); 60 } 61 62 /* 測試*/ 63 int main() 64 { 65 66 /* 構建樹結構如下: 67 1 68 / \ 69 2 3 70 / \ 71 4 5 72 */ 73 struct tNode *root = newtNode(1); 74 root->left = newtNode(2); 75 root->right = newtNode(3); 76 root->left->left = newtNode(4); 77 root->left->right = newtNode(5); 78 79 MorrisTraversal(root); 80 return 0; 81 }
?