轉載自 http://blog.csdn.net/quzhongxin/article/details/46315251
Binary Tree Preorder Traversal:https://leetcode.com/problems/binary-tree-preorder-traversal/
Binary Tree Inorder Traversal :https://leetcode.com/problems/binary-tree-inorder-traversal/
Binary Tree Postorder Traversal:https://leetcode.com/problems/binary-tree-postorder-traversal/
- 前序遍歷:先訪問該節點,然後訪問該節點的左子樹和右子樹;
- 中序遍歷:先訪問該節點的左子樹,然後訪問該節點,再訪問該節點的右子樹;
- 後序遍歷:想訪問該節點的左子樹和右子樹,然後訪問該節點。
遞歸遍歷
對於遞歸遍歷比較簡單:
void preorder(TreeNode* root) {
if (root == NULL)
return;
visit(root);
preorder(root->left);
preorder(root->right);
}
void inorder(TreeNode* root) {
if (root == NULL)
return;
inorder(root->left);
visit(root);
inorder(root-<right);
}
void postorder(TreeNode* root) {
if (root == NULL)
return;
postorder(root->left);
postorder(root->right);
visit(root);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
非遞歸(迭代)遍歷
非遞歸實現在遍歷根節點後還要回來,因此要基於棧(先進後出)來保存節點。
注:二叉樹遍歷的非遞歸實現文章裏有不同的實現方式,更易於理解記憶。
前序遍歷
壓入順序:右子樹->左子樹->根節點
使得訪問的時候的順序成爲:根->左子樹->右子樹
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> s;
if (root == NULL)
return result;
s.push(root);
while(!s.empty()) {
TreeNode* p = s.top();
s.pop();
result.push_back(p->val);
if (p->right)
s.push(p->right);
if (p->left)
s.push(p->left);
}
return result;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
中序遍歷
壓入順序:右子樹->根->左子樹
只有當左子樹已經訪問完後,才能訪問根節點
對於任一結點P,
1)若其左孩子不爲空,則將P入棧並將P的左孩子置爲當前的P,然後對當前結點P再進行相同的處理;
2)若其左孩子爲空,則取棧頂元素並進行出棧操作,訪問該棧頂結點,然後將當前的P置爲棧頂結點的右孩子;
3)直到P爲NULL並且棧爲空則遍歷結束
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> s;
if (root == NULL)
return result;
TreeNode* p = root;
while (!s.empty() || p != NULL) {
if (p != NULL) {
// push 左子樹入棧
s.push(p);
p = p->left;
} else {
// 左子樹爲空時,訪問該節點,然後訪問右子樹
p = s.top();
result.push_back(p->val);
s.pop();
p = p->right;
}
}
return result;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
後序遍歷
先壓入根,然後是右子樹,最後左子樹
要求最後訪問根節點,即訪問該根節點時必須訪問完左子樹和右子樹,我們只需要保證訪問某一節點時,該節點的右子樹已經被訪問,否則需要將該節點重新壓入棧。
對於任一結點P,將其入棧,然後沿其左子樹一直往下搜索,直到搜索到沒有左孩子的結點,此時該結點出現在棧頂,但是此時不能將其出棧並訪問,因此其右孩子還爲被訪問。所以接下來按照相同的規則對其右子樹進行相同的處理,當訪問完其右孩子時,該結點又出現在棧頂,此時可以將其出棧並訪問。這樣就保證了正確的訪問順序。可以看出,在這個過程中,每個結點都兩次出現在棧頂,只有在第二次出現在棧頂時,才能訪問它。
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
if (root == NULL)
return result;
stack<TreeNode*> s;
TreeNode* p = root; //當前正訪問的節點
TreeNode* q; //記錄剛剛訪問過的節點
do{
while (p != NULL) {
s.push(p);
p = p->left;
}
q = NULL;
while (!s.empty()) {
p = s.top();
s.pop();
if (p->right == q) { //當右子樹已經訪問過了,纔可以訪問根
result.push_back(p->val);
q = p; //記錄剛剛訪問過的節點
} else {
s.push(p); //第一次訪問到該節點,需要將它重新入棧
p = p->right;
break;
}
}
} while (!s.empty());
return result;
}
- 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
- 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
參考資料
二叉樹的非遞歸遍歷 http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html