參考博客
/*
* 二叉樹的先序遍歷 --- 非遞歸版與遞歸版
*/
#include <iostream>
#include <stack>
using namespace std;
struct TreeNode{
int val;
TreeNode* left, *right;
TreeNode(int v = 0) : val(v), left(NULL), right(NULL){}
};
void visit(TreeNode* p){ //訪問函數,這里簡單只設為是打印
cout << p->val << " ";
}
/*******************************************
* 前序遍歷
********************************************/
void BT_PreOrder(TreeNode* root){
if(root == NULL) return;
stack<TreeNode*> S;
S.push(root);
while(!S.empty()){
TreeNode* cur = S.top();
S.pop();
visit(cur); //訪問
if(cur->right) S.push(cur->right);
if(cur->left) S.push(cur->left);
}
return;
}
/*******************************************
* 中序遍歷
********************************************/
void BT_InOrder(TreeNode *root){
stack<TreeNode* > S;
TreeNode *cur = root;
while(true){
while(cur){
S.push(cur); cur = cur->left;
}
if(S.empty()) break;
cur = S.top();
visit(cur);
S.pop();
cur = cur->right;
}
}
/*******************************************
* 后序遍歷
********************************************/
void findFirst(stack<TreeNode*> &S); //找到以棧頂節點為根的子樹其第一個應該輸出的節點
//即按照自己-右節點-左節點的順序壓棧
void BT_PostOrder(TreeNode* root){
if(root == NULL) return;
stack<TreeNode *> S;
TreeNode *cur = root;
S.push(root);
while(!S.empty()){
if(S.top()->left != cur && S.top()->right != cur){ //當前節點不是棧頂節點的子節點
//這里的當前節點指的是上一個輸出的節點
//這種關系表示上一個輸出節點是左節點,而棧頂是右節點,因為右節點可能有未輸出的子樹,因此需要進行FindFirst的操作
findFirst(S);
}
visit(cur = S.top());
S.pop();
}
}
void findFirst(stack<TreeNode*> &S) {
//找到以棧頂節點為根的子樹其第一個應該輸出的節點
while (TreeNode* x = S.top()) {
if (x->left) { //一句話總結,有左先右再左,無左只壓右
if (x->right) S.push(x->right);
S.push(x->left);
}
else {
S.push(x->right);
}
}
S.pop(); //刪掉棧頂的空指針
}
//前序遍歷的遞歸定義:先根節點,后左子樹,再右子樹。
//首先,我們遍歷左子樹,邊遍歷邊打印,并把根節點存入棧中,以后需借助這些節點進入右子樹開啟新一輪的循環。
void my_pre(TreeNode* root){
if(root == NULL)
return;
TreeNode* p = root;
stack<TreeNode*> s;
while(p||!s.empty()){
while(p){
visit(p);
s.push(p);
p=p->left;
}
if(!s.empty()){
p = s.top();
s.pop();
p = p->right;
}
}
}
void my_in(TreeNode* root){
if(root == NULL)
return;
TreeNode* p = root;
stack<TreeNode*> s;
while(p||!s.empty()){
//一直遍歷到左子樹最下邊,邊遍歷邊保存根節點到棧中
if(p){
s.push(p);
p=p->left;
}
//當p為空時,說明已經到達左子樹最下邊,這時需要出棧了
else{
p = s.top();
s.pop();
visit(p);
//進入右子樹,開始新的一輪左子樹遍歷(這是遞歸的自我實現)
p = p->right;
}
}
}
/*
0
|
+ 2 ----- 6
| +---- 5 ---- 10
| + ---- 9
+ 1 ----- 4 ---- 8
+ ---- 7
+---- 3
*/
int main(){
TreeNode n0(0), n1(1), n2(2), n3(3), n4(4),n5(5), n6(6), n7(7),n8(8), n9(9),n10(10);
n0.left = &n1; n0.right = &n2;
n1.left = &n3; n1.right = &n4;
n2.left = &n5; n2.right = &n6;
n4.left = &n7; n4.right = &n8;
n5.left = &n9; n5.right = &n10;
BT_PreOrder(&n0);
cout << endl;
my_pre(&n0);
cout << endl;
BT_InOrder(&n0);
cout << endl;
my_in(&n0);
cout << endl;
BT_PostOrder(&n0);
cout << endl;
}
二叉樹的非遞歸后續遍歷
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> result;
TreeNode* p = root;
TreeNode* q = nullptr; //用來保存剛訪問過的節點
do{
while(p!=nullptr){ //往左下走到底
s.push(p);
p = p->left;
}
q = nullptr;
while(!s.empty()){
p = s.top();
s.pop();
if(p->right == q){ //p為左孩子或者說是可以訪問的父節點(右子樹已被訪問)
result.push_back(p->val);
q = p; // 保存剛剛訪問過的節點
}
else { // 當前節點不能訪問,需要第二次進棧
s.push(p);
p = p->right; //先處理右子樹
break;
}
}
}while(!s.empty());
return result;
}
};