二叉樹(建立與訪問)(先序,中序,後序)
阿新 • • 發佈:2018-11-08
二叉樹的建立(先序建立)
二叉樹的訪問(遞迴與非遞迴 先序)(遞迴與非遞迴中序)(遞迴與非遞迴 後序)
#include<iostream> #include<stack> using namespace std; struct Tree_Node ///結點的結構 { char data; ///每個結點的資料 Tree_Node * left; ///左子樹 Tree_Node * right; ///右孩子 }; ///按照先序遍歷的方式,構建我們的二叉樹,輸入的時候, ///我們要按照完全二叉樹的形式輸入,結點為空的位置,輸入“#” void createTree(Tree_Node *&t) { char str; cin>>str; if(str=='#') { t=NULL; } else { t=new Tree_Node; ///為t開闢空間 t->data = str; createTree(t->left); createTree(t->right); } } void PreorderTraverse(Tree_Node * T)///先序遍歷,遞迴實現 { if(T) { if(T->data!='#') cout<<T->data<<" "; ///訪問根結點 PreorderTraverse(T->left); ///訪問左子樹 PreorderTraverse(T->right); ///訪問右子樹 } } ///非遞迴實現,思路: ///首先我們的迴圈條件是:結點不為空或者棧不為空。 ///然後是先把根結點加入桟中,然後,遍歷左子樹,當左子樹遍歷完後,棧頂元素為剛剛的根結點, ///然後,讓根結點出棧,遍歷右子樹 void PreorderTraverse_no_recursive(Tree_Node * T) { stack<Tree_Node*> s; Tree_Node *p = T; ///棧不為空或者T不為空時,迴圈繼續 while(p || !s.empty()) { if(p!=NULL) { s.push(p); ///根結點入棧 if(p->data!='#')///訪問根結點 cout<<p->data<<' '; p = p->left; ///先遍歷左子樹 } else { p = s.top(); ///根結點出棧 s.pop(); p = p->right;///遍歷右子樹 } } } void InorderTraverse(Tree_Node * T)///遞迴實現中序遍歷 { if(T) { InorderTraverse(T->left); ///中序遍歷左孩子 if(T->data!='#') cout<<T->data<<" "; ///訪問根結點 InorderTraverse(T->right); ///中序遍歷右孩子 } } ///非遞迴實現中序遍歷,思路: ///思路:T是要遍歷樹的根指標,中序遍歷要求在遍歷完左子樹後,訪問根,再遍歷右子樹。 ///先將T入棧,遍歷左子樹;遍歷完左子樹返回時,棧頂元素應為T,出棧,訪問T->data, ///再中序遍歷T的右子樹。 void InorderTraverse_recursive(Tree_Node * T) { stack<Tree_Node*> s; Tree_Node * p=T; ///棧不為空或者T不為空時,迴圈繼續 while(p || !s.empty()) { if(p!=NULL) { s.push(p); ///根結點入棧 p = p->left; ///先遍歷左子樹 } else { p=s.top(); ///根結點出棧 s.pop(); if(p->data!='#') cout<<p->data<<' ';///訪問根結點 p = p->right;///遍歷右子樹 } } } void PostorderTraverse(Tree_Node * T)///遞迴實現後序遍歷 { if(T) { PostorderTraverse(T->left); ///訪問左子樹 PostorderTraverse(T->right); ///訪問右子樹 if(T->data!='#') cout<<T->data<<" "; ///訪問根結點 } } ///非遞迴實現後序遍歷 ///思路:我們要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點P,先將其入棧。 ///如果P不存在左孩子和右孩子,則可以直接訪問它; ///或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,則同樣可以直接訪問該結點。 ///若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候, ///左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。 void PostorderTraverse_recursive(Tree_Node * T) { Tree_Node *pre; ///前一個被訪問的結點。 pre=NULL; stack<Tree_Node*> s; Tree_Node *cur; ///記錄棧頂的結點, s.push(T); ///先把根結點入棧 while(!s.empty()) { cur=s.top(); ///cur記錄的是棧頂的結點 if((cur->left==NULL && cur->right==NULL) || (pre!=NULL && (pre==cur->left || pre==cur->right))) { cout<<cur->data<<" "; ///滿足:不存在左孩子和右孩子;或者存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了 s.pop(); pre=cur; ///更新pre的值 } else { if(cur->right!=NULL) s.push(cur->right); ///一定是右子樹先入棧的,因為這樣才可以比左子樹後被訪問 if(cur->left!=NULL)s.push(cur->left); ///左子樹入棧 } } } int main() { Tree_Node * T; createTree(T); cout<<"先序遍歷--遞迴實現"<<endl; PreorderTraverse(T); cout<<endl; cout<<"先序遍歷--非遞迴實現"<<endl; PreorderTraverse_no_recursive(T); cout<<endl; cout<<"中序遍歷--遞迴實現"<<endl; InorderTraverse(T); cout<<endl; cout<<"中序遍歷--非遞迴實現"<<endl; InorderTraverse_recursive(T); cout<<endl; cout<<"後序遍歷--遞迴實現"<<endl; PostorderTraverse(T); cout<<endl; cout<<"後序遍歷--非遞迴實現"<<endl; PostorderTraverse_recursive(T); cout<<endl; return 0; }