1 // 實現后序遍歷的非遞歸 2 // 核心:一個結點需要彈出兩次,第一次彈出的時候還需要放回原位(左子樹遍歷完畢),第二次彈出的時候才輸出其值(右子樹遍歷完畢); 3 4 5 #include <iostream> 6 #include <stack> 7 using namespace std; 8 9 struct node { 10 int data; 11 struct node* left = nullptr; 12 struct node* right = nullptr; 13 int times = 0; //當計數值到達2時,不再進入棧中; 14 }; 15 16 typedef struct node node; 17 18 void init(node& head) { 19 head.data = 1; 20 21 head.left = new node(); 22 head.left->data = 2; 23 24 head.left->left = new node(); 25 head.left->left->data = 3; 26 27 head.left->left->left = new node(); 28 head.left->left->left->data = 4; 29 30 head.left->right = new node(); 31 head.left->right->data = 5; 32 33 head.left->right->left = new node(); 34 head.left->right->left->data = 6; 35 36 head.right = new node(); 37 head.right->data = 7; 38 } 39 40 int main() { 41 node head; 42 43 init(head); 44 45 stack<node*> s; 46 47 node* p = &head; 48 49 while (p != nullptr || !s.empty()) { 50 // 入棧 51 if (p != nullptr) { 52 s.push(p); 53 p = p->left; 54 } 55 56 // 出棧 57 if (p == nullptr) { 58 p = s.top(); 59 s.pop(); 60 61 p->times++; 62 63 //遍歷右子樹 64 if (p->times == 1) { 65 s.push(p); 66 p = p->right; 67 } 68 69 //p.times==2; 繼續彈棧 70 else { 71 cout << p->data; 72 p = nullptr; // 回溯的關鍵步驟 73 } 74 } 75 } 76 77 return 0; 78 }
關鍵點:
- 當該結點為非空,進行訪問左結點;
- 當這個元素出棧時,需要考慮其訪問次數:如果次數為1,那么需要將其再次入棧,然后遍歷右子樹。如果次數為2,那么表示以該節點為跟的子樹訪問完畢,置為null。
- 上述的核心遍歷代碼是對不同的結點以出棧和入棧為單位(遇到非空,進行入棧;遇到空,進行出棧,並進行完整的后序操作),每一次循環對一個結點進行一次完整的操作。 而下列代碼主要是以一次操作為單位。
1 while (p != nullptr || !s.empty()) { 2 if (p == nullptr) { 3 p = s.top(); 4 s.pop(); 5 p->times++; 6 } 7 else { 8 // 該結點為根的樹已經遍歷,相當於NULL 9 if (p->times == 2) { 10 cout << p->data << " "; 11 p = nullptr; 12 } 13 else if(p->times==1) { 14 s.push(p); 15 p = p->right; 16 } 17 else { 18 s.push(p); 19 p = p->left; 20 } 21 } 22 }