數據結構筆記之(1)——樹的三種遍歷


轉載請注明:http://www.cnblogs.com/igoslly/p/7864406.html

樹的三種遍歷

  當接觸樹后,自然而然會接觸樹的遍歷。

    樹的遍歷共分為3種先序遍歷中序遍歷后序遍歷,這里的“為根節點的遍歷順序

  故而遍歷順序可理解為:

    先序遍歷:根節點 →左子樹 → 右子樹,在子樹中繼續應用左子樹 → 根節點 → 右子樹;

    中序遍歷:左子樹 → 根節點 → 右子樹,同理

    后序遍歷:左子樹 → 右子樹 → 根節點,同理

 

  那如此拋出一個問題:給定樹后確定遍歷序列,那能否從遍歷序列恢復原樹呢?

    單一遍歷序列的話,答案肯定是否定的 —— 因為單孩子情況中無法確定為左孩子還是右孩子。

  給定兩個遍歷序列的話,能否唯一確定呢?

    1、先序+中序: 先序最頭找到根節點root,中序找到root所在的位置,序列[0,root-1]即為左子樹[root+1,length-1]即為右子樹,如此遞推;

    2、中序+后序:后序最末找到根節點root,同理;

  通過上面兩種情況,可以發現:

    先序遍歷在確定樹左、右子樹情況時起到了至關重要的作用。

    3、先序+后序:不唯一確定,因為根節點單孩子情況下,先序和后序並無分別。

 

  那我們題目想實現的是:如果給出了先序序列和中序序列,代碼如何去實現?

      遍歷和構建樹的實現無非是遞歸函數,重要是確定遞歸結束的條件。

  首先先給出是三種遍歷方式的實現方式:

//先序遍歷
void preOrder(Tree * bt){
      if(bt!=NULL){
           visit(bt->data);
           preOrder(bt->lChild);
           preOrder(bt->rChild);
    }       
}

//中序遍歷
void inOrder(Tree * bt){
      if(bt!=NULL){
           inOrder(bt->lChild);
           visit(bt->data);
           inOrder(bt->rChild);
    }       
}

//后序遍歷
void postOrder(Tree * bt){
      if(bt!=NULL){
           postOrder(bt->lChild);
           postOrder(bt->rChild);
           visit(bt->data);
    }       
}

 

  在通過先序+中序的根節點分開法中,有人也將其稱之為分而治之法,直接將序列分為左子樹和右子樹考慮:

      也就是左子樹 index from [ 0, root-1 ],右子樹 index from [ root+1, length-1 ]

  下面給出的只是我不成熟的實現方法:

// 主函數main
// 給出先序序列、中序序列,大家可手動畫一下樹圖
// 建立樹,再后續遍歷輸出

int main(){
    int pre[]={1,2,3,4,5,6,7};
    int in[]={3,2,4,1,6,5,7};
    Tree * head=init();
    int put=0;
    createTree(pre,in,0,6,head,&put);
    post(head);
}

 

    樹的初始化方法即:設定一個空數據的head頭結點

    定義find函數,找到在中序遍歷中根節點的所在位置root

Tree * init(){
    Tree * head=(Tree *)malloc(sizeof(Tree));
    head->left=NULL;
    head->right=NULL;
    return head;
}

int find(int in[],int x){
    int i=0;
    while(1){
        if(in[i]==x){
            cout<<x<<" in pre array's index is "<<i<<endl;
            return i;
        }
        i++;
    }
    return 0;
}

 

    然后是遞歸主題部分,個人也覺得寫的有點繁瑣了,可以簡單看看

void createTree(int pre[],int in[],int leftindex,int rightindex,Tree * head,int *put){
    int root=find(in,pre[*put]);
    head->data=pre[*put];
    // 只剩單一元素,返回上層結點 
    if(leftindex==rightindex){
        return;
    }
    if(root!=leftindex){
        Tree * p=(Tree *)malloc(sizeof(Tree));
        p->left=NULL;
        p->right=NULL;
        head->left=p;
        cout<<"Now looking for "<<head->data<<" 's leftChild in arrayindex [ "<<leftindex<<", "<<root-1<<" ], put ="<<*put<<endl; 
        (*put)++;
        createTree(pre,in,leftindex,root-1,p,put);
    }
    if(root!=rightindex){
        Tree * q=(Tree *)malloc(sizeof(Tree));
        q->left=NULL;
        q->right=NULL;
        head->right=q;
        cout<<"Now looking for "<<head->data<<" 's rightChild in arrayindex [ "<<root+1<<", "<<rightindex<<" ], put ="<<*put<<endl; 
        (*put)++;
        createTree(pre,in,root+1,rightindex,q,put);
    }
}

 

    在程序中,我插入了許多實時顯示運行狀態的語句,方便更好地理解和調試;

    就比如在下語句時,我原本寫的是 * put++ ,使*put=0直接下函數取3,成功找出錯誤;

(*put)++;

    可以看到完整的構建過程,由於put指針傳遞,值持續增加,當然可以采用全局或者靜態變量形式;

 


 申明:

1、本筆記為文字及圖片均為個人原創,轉載請注明博客園-igoslly

2、此題為2017年11月參與數據結構習題時實現


免責聲明!

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



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