二叉樹——前、中、後序遍歷遞迴以及非遞迴寫法
阿新 • • 發佈:2018-12-13
#include <iostream> #include <stack> #include <queue> using namespace std; typedef struct Node{ int data; Node *lchild; Node *rchild; Node() { data = 0; lchild = NULL; rchild = NULL; } }BiTree,*BTree; //前序建立二叉樹 void CreatBiTree(BTree& T,char data) { cout<<"父節點:"<<data<<endl; char c; cin>>c; if(c =='#') { T=NULL; }else { T = new BiTree; T->data = c; CreatBiTree(T->lchild,T->data); CreatBiTree(T->rchild,T->data); } return; } /* 樹形 ############# 1 2 5 3 4 6 7 ############# 前序: 1 2 3 4 5 6 7 中序: 3 2 4 1 6 5 7 後序: 3 4 2 6 7 5 1 */ //建立二叉樹 void CreatTree(BTree& T) { T = new BiTree; T->data = 1; //左子樹 BTree T1 = new BiTree; T1->data = 2 ; T->lchild = T1; BTree T11 = new BiTree; T11->data = 3; T1->lchild = T11; BTree T12 = new BiTree; T12->data = 4; T1->rchild = T12; //右子樹 BTree T2 = new BiTree; T2->data = 5 ; T->rchild = T2; BTree T21 = new BiTree; T21->data = 6; T2->lchild = T21; BTree T22 = new BiTree; T22->data = 7; T2->rchild = T22; return; } //前序遞迴遍歷 void PreOrderBiTree(BiTree* T) { if(T) { cout<<T->data <<" ";; PreOrderBiTree(T->lchild); PreOrderBiTree(T->rchild); } } //非遞迴前序《1》 /***************** 先將右子樹放入棧底,依次放入左子樹元素 按照左節點在上右節點在下原則 遇到葉節點 即開始彈出棧內元素 ******************/ void PreOredrTree1(BiTree *T) { BiTree* p = T; stack<BiTree*> S; //棧空間 S.push(p); while(!S.empty()) { p = S.top(); S.pop(); cout<<p->data<<" "; if(p->rchild) //右子樹節點入棧底 S.push(p->rchild); if(p->lchild) //左子樹節點入棧 S.push(p->lchild); } return ; } //非遞迴前序《2》王道寫法 /***************** 將所有的左子樹的左子節點入棧 同時 輸出值 棧頂的左子節點出棧,訪問其右節點, 若有 輸出其值 入棧 同時繼續將該節點的左子樹左節點入棧 若無,繼續彈出下一個棧元素,訪問其右節點 ******************/ void PreOredrTree(BiTree *T) { BiTree* p = T; stack<BiTree*> S; //棧空間 while(!S.empty()||p!=NULL) { if(p) { cout<< p->data <<" "; S.push(p); p = p->lchild; } else{ p = S.top(); S.pop(); p = p->rchild; } } return ; } //層序遍歷 void LeveOredrTree(BiTree *T) { BiTree* p = T; queue<BiTree*> S; S.push(p); while(!S.empty()) { p = S.front(); S.pop(); cout<<p->data<<endl; if(p->lchild) S.push(p->lchild); if(p->rchild) S.push(p->rchild); } return ; } //中序遞迴遍歷 void InOrderBiTree(BiTree* T) { if(T) { InOrderBiTree(T->lchild); cout<<T->data <<" "; InOrderBiTree(T->rchild); } } //非遞迴中序《1》王道寫法 左根右 /***************** 將所有的左子樹的左子節點入棧 棧頂的左子節點出棧 <<<<輸出其值>>>> 訪問其右節點, //區別在於此!! 若有 入棧 同時繼續將該節點的左子樹左節點入棧 若無,繼續彈出下一個棧元素,再訪問其右節點 ******************/ void InOrderTree(BiTree *T) { BiTree* p = T; stack<BiTree*> S; //棧空間 while(!S.empty()||p!=NULL) { if(p) { S.push(p); p = p->lchild; } else{ p = S.top(); cout<< p->data <<" "; S.pop(); p = p->rchild; } } return ; } //後序遞迴遍歷 void PostOrderBiTree(BiTree* T) { if(T) { PostOrderBiTree(T->lchild); PostOrderBiTree(T->rchild); cout<<T->data <<" "; } } //非遞迴後序《1》王道寫法 左右根 /***************** 將所有的左子樹的左子節點入棧 棧頂最後一個左節點出棧,判斷其是否還有右根, 若有,右根入棧 同時繼續將該右根的左子樹的所有左節點入棧 若無,彈出該節點,輸出其值,同時記錄該節點? 用做此的父節點出棧時的對比,避免此 節點 重複入棧 ******************/ void PostOrderTree(BiTree *T) { BiTree* p = T; BiTree* k = NULL;//用於標記改節點是否已經訪問其右節點 stack<BiTree*> S; //棧空間 while(!S.empty()||p!=NULL) { if(p) { S.push(p); p = p->lchild; } else{ p = S.top(); //先不出棧 if(p->rchild != NULL && k != p->rchild)//判斷p出棧時p的右子樹有無入棧(沒有:p不能出棧,繼續將右子樹入棧。有:p可以出棧 ) { p = p->rchild; //繼續將右節點的所有子樹左節點入棧 } else{ cout<< p->data<<" ";//輸出節點值 S.pop(); //節點出棧 k = p; p = NULL; } } } return ; } int main() { BiTree* T; CreatTree(T); cout<<"建立二叉樹完成!"<<endl; cout<<"前序遍歷二叉樹: 1 2 3 4 5 6 7 "<<endl; PreOrderBiTree(T); cout<<endl<<"非遞迴前序遍歷二叉樹!"<<endl; PreOredrTree(T); cout<<endl<<"中序遍歷二叉樹: 3 2 4 1 6 5 7 "<<endl; InOrderBiTree(T); cout<<endl<<"非遞迴中序遍歷二叉樹!"<<endl; InOrderTree(T); cout<<endl<<"後序遍歷二叉樹: 3 4 2 6 7 5 1"<<endl; PostOrderBiTree(T); cout<<endl<<"非遞迴後序遍歷二叉樹!"<<endl; PostOrderTree(T); cout<<endl; system("pause") ; return 0; }