二叉樹的創建和遍歷


【問題描述】 給出一個按照先序遍歷得出的字符串,'#' 代表空的子節點,大寫字母代表節點內容。請通過這個字符串建立二叉樹,並采用非遞歸的先序、中序、后序遍歷 的算法分別輸出每一個非空節點。
【輸入形式】輸入只有一行,包含一個字符串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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM