【問題描述】 給出一個按照先序遍歷得出的字符串,'#' 代表空的子節點,大寫字母代表節點內容。請通過這個字符串建立二叉樹,並采用非遞歸的先序、中序、后序遍歷 的算法分別輸出每一個非空節點。
【輸入形式】輸入只有一行,包含一個字符串S,用來建立二叉樹。保證S為合法的二叉樹先序遍歷字符串,節點內容只有大寫字母,且S的長度不超過100。
【輸出形式】 共有三行,每一行包含一串字符,表示分別按非遞歸的先序、中序、后序遍歷得出的節點內容,每個字母后輸出一個空格。請注意行尾輸出換行。
【樣例輸入】 ABC##DE#G##F###
【樣例輸出】
A B C D E G F
C B E G D F A
C G E F D B A
#include<bits/stdc++.h> using namespace std; #define N 20 typedef struct Tree{ char data; struct Tree *LeftChild; struct Tree *RightChild; }BiTNode, *BiTree; BiTree CreateTree(){ BiTree tree; char ch; cin>>ch; if(ch=='#'){return NULL;} else{ tree=(BiTree)malloc(sizeof(BiTNode)); tree->data=ch; tree->LeftChild=CreateTree(); tree->RightChild=CreateTree(); return tree;//在這里return } } void NPreOrder(BiTree bt){ BiTree *s;//相當於 BiTNode**s BiTree p; int top=-1; //創建棧 s=(BiTree*)malloc((N+1)*sizeof(BiTree)); s[++top]=bt;//s[0]=bt top=0 while(top!=-1){ p=s[top--]; cout<<p->data;//輸出s[top] top再--(第一次是直接輸出s[0],top=-1了) if(p->RightChild){ s[++top]=p->RightChild;//讓新的二叉樹節點進棧,得是先++top(第一次top=-1了都)(s[0]=新的) } if(p->LeftChild){ s[++top]=p->LeftChild;//這里 必須先是右節點進棧 再是左節點進棧 自己想一下 } } } void YPreOrder(BiTree bt){ //前序遞歸遍歷中左右 if(bt){ cout<<bt->data; YPreOrder(bt->LeftChild); YPreOrder(bt->RightChild);//這里就是先遞歸左孩子再是右孩子了 } } void NInOrder(BiTree bt){ BiTree *s; BiTree p,q; s=(BiTree*)malloc((N+1)*sizeof(BiTree)); int top=-1;//top==-1就是棧空的意思 if(bt){ while(bt){ s[++top]=bt; bt=bt->LeftChild; } //左子樹全部進棧(到最左的葉子節點了) while(top!=-1){//棧不空 p=s[top--];//取出棧頂元素(其實就是左下角的樹節點) cout<<p->data; while(p->RightChild){//看看這個節點是否有右孩子 q=p->RightChild; s[++top]=q;//有則賦給q 進棧 while(q->LeftChild){ //顆顆q有沒有左孩子 s[++top]=q->LeftChild; q=q->LeftChild; } break;//while語句里的break就是直接跳出這個while循環 所以接下來就是看這個q有沒有右孩子( 看上面的qwhile 有左孩子的話那也全進棧了 ) } } } } void YInOrder(BiTree bt){ if(bt){ YInOrder(bt->LeftChild); cout<<bt->data; YInOrder(bt->RightChild); } } /* 后序遍歷的非遞歸算法是三種順序中最復雜的,原因在於,后序遍歷是先訪問左、右子樹,再訪問根節點, 而在非遞歸算法中,利用棧回退到時,並不知道是從左子樹回退到根節點,還是從右子樹回退到根節點, 如果從左子樹回退到根節點,此時就應該去訪問右子樹, 而如果從右子樹回退到根節點,此時就應該訪問根節點。 所以相比前序和后序,必須得在壓棧時添加信息, 以便在退棧時可以知道是從左子樹返回,還是從右子樹返回進而決定下一步的操作 */ void NPostOrder(BiTree bt){ BiTree *s; BiTree p,q; q=NULL; s=(BiTree*)malloc((N+1)*sizeof(BiTree)); int top=-1; while(bt!=NULL||top!=-1){ if(bt){ s[++top]=bt; bt=bt->LeftChild; }//這個if在這里是可以的(對比while) 也遍歷完左邊的樹節點了啊 因為if滿足不會執行下面的else語句 就會一直執行if else{ bt=s[top];//先把棧頂元素拿出來試探一下 if(bt->RightChild==NULL||bt->RightChild==q){//無右孩子或者右孩子已經遍歷過了 cout<<bt->data; q=bt;//保存到q,為下一次已處理節點前驅 top--; bt=NULL; /*bt是一直用來動的節點,這個最后賦值為空的目的是 已知在這個條件下,該去訪問中間節點了, 如何訪問呢,只能往回走,就是看看棧的情況,怎么看棧的情況,只能滿足第二個條件不滿第一個*/ } else{//正經遍歷右節點 bt=bt->RightChild; } } } } void YPostOrder(BiTree bt){ if(bt){ YInOrder(bt->LeftChild); YInOrder(bt->RightChild); cout<<bt->data; } } int main(){ BiTree pt; cout<<"創建二叉樹"<<endl; pt=CreateTree(); cout<<"前序非遞歸遍歷:"<<endl; NPreOrder(pt); cout<<endl; cout<<"前序遞歸遍歷"<<endl; YPreOrder(pt); cout<<endl; cout<<"中序非遞歸遍歷:"<<endl; NInOrder(pt); cout<<endl; cout<<"中序遞歸遍歷:"<<endl; YInOrder(pt);cout<<endl; cout<<"后序非遞歸遍歷"<<endl; NPostOrder(pt);cout<<endl; cout<<"后序遞歸遍歷"<<endl; YPostOrder(pt);cout<<endl; }