二叉樹遍歷非遞迴寫法之大統一
在學習二叉樹遍歷時,大家都很容易接受遞迴寫法,好理解。對於非遞迴寫法,基本思想是用棧消除遞迴,但是教材上的前序、中序和後序基本上三個寫法,還很難理解。博主親身經歷,找工作中,考查二叉樹遍歷的非遞迴寫法還是常見的。所以決心整理出此文,方便理解和記憶二叉樹遍歷。
來複習一下二叉樹的遞迴遍歷。
- struct TreeNode {
- int data;
- TreeNode * left, * right;
- };
-
void preOrderTraverse(TreeNode * root, void (*visit)(TreeNode *)) {
- if (root) {
- visit(root);
- preOrderTraverse(root->left, visit);
- preOrderTraverse(root->right, visit);
- }
- }
- void inOrderTraverse(TreeNode * root, void (*visit)(TreeNode *)) {
- if (root) {
- inOrderTraverse(root->left, visit);
-
visit(root);
- inOrderTraverse(root->right, visit);
- }
- }
- void postOrderTraverse(TreeNode * root, void (*visit)(TreeNode *)) {
- if (root) {
- postOrderTraverse(root->left, visit);
- postOrderTraverse(root->right, visit);
- visit(root);
- }
- }
首先,博主找到了一篇類似論文,
本文意圖使用常見的二叉樹遍歷的形式,簡潔的實現這三種遍歷。
void preOrderTraverseNonrecursive(TreeNode * root, void (*visit)(TreeNode *)) {
stack<TreeNode *> s;
TreeNode * p = root;
while(p != NULL || !s.empty()) {
while(p != NULL) {
visit(p);
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
p = p->right;
s.pop();
}
}
}
void inOrderTraverseNonrecursive(TreeNode * root, void (*visit)(TreeNode *)) {
stack<TreeNode *> s;
TreeNode * p = root;
while(p != NULL || !s.empty()) {
while(p != NULL) {
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
visit(p);
p = p->right;
s.pop();
}
}
}
void postOrderTraverseNonrecursive(TreeNode * root, void (*visit)(TreeNode *)) {
stack<TreeNode *> s;
TreeNode * p = root, *pre = NULL;
while(p != NULL || !s.empty()) {
while(p != NULL) {
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
if( p->right == NULL ||
p->right == pre) {
visit(p);
pre = p;
p = NULL;
s.pop();
}
else {
p = p->right;
}
}
}
}
在前序遍歷的程式碼中,最外層是while迴圈直到棧空且p為空,裡面的while迴圈,不停訪問根節點p,且迭代p=p->right,直到p為空。此時,從root開始的所有左分支的根節點均已被訪問。到if分支時,取棧頂節點,切換到其右子樹開始迭代。
前序遍歷和中序遍歷區別僅在於visit函式的呼叫位置不同。中序和後序的區別在於呼叫visit的時機不一致。教材上的實現中,後序遍歷需要一個標誌來記錄當前節點是否被訪問過。在本文的實現中,通過一個pre指標記錄被訪問的最後一個元素,通過p->right==pre的比較來確認p是否被訪問過。當然,直接訪問p的另一情形是p沒有右孩子。在這樣的實現下,中序和後序的區別儘可能小。三種實現中,程式碼結構較一致,只有較少的變動。
希望本文可以方便那些學習非遞迴遍歷二叉樹的同學。
歡迎大家留言討論!