PAT甲題題解-1119. Pre- and Post-order Traversals (30)-(根據前序、后序求中序)


(先說一句,題目還不錯,很值得動手思考並且去實現。)

題意:根據前序遍歷和后序遍歷建樹,輸出中序遍歷序列,序列可能不唯一,輸出其中一個即可。  

  已知前序遍歷和后序遍歷序列,是無法確定一棵二叉樹的,原因在於如果只有一棵子樹可能是左孩子也有可能是右孩子。由於只要輸出其中一個方案,所以假定為左孩子即可。下面就是如何根據前序和后序划分出根節點和左右孩子,這里需要定義前序和后序的區間范圍,分別為[preL,preR],[postL,postR]。  

  一開始區間都為[1,n],可以發現前序的第一個和后序的最后一個為根節點root,前序的第二個值val為其某子樹的根節點(但還無法確定是左孩子or右孩子)。在后序中找對應的值所在的位置postIdx,則postIdx之前的節點均為val的孩子節點,統計其個數num。那么我們就可以划分區間:  

若num個數=preR-preL-1,即val后面的個數都是其子節點,那么二叉樹不唯一,將其作為root的左子樹處理。

否則划分為左子樹區間和右子樹對應的前序和后序區間,順便更新下root的左孩子preL+1,右孩子preL+num+2:
preOrder:[preL+1,preL+num+1],postOrder:[postL,postIdx];
preOrder:[preL+num+2,preR],postOrder:[postIdx+1,postR-1];
然后遞歸划分即可


拿樣例舉例:
1 (2) [3 {4 6 7} <5>]
(2) [{6 7 4} <5> 3] 1
不同的括號對應不同的子樹區間
第一次遞歸划分了(2)-(2),[3 4 6 7 5]-[6 7 4 5 3]
由於(2)只有一棵,不繼續划分。
第二次遞歸划分了{4 6 7}-{6 7 4},<5>-<5>
第三次遞歸划分了(6)-(6),(7)-(7)
結束

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>

using namespace std;
const int maxn=35;
int preOrder[maxn];
int postOrder[maxn];
bool isUnique=true;
struct Node{
    int left=-1,right=-1;
}node[maxn];

/*
[preL,preR] is current sequence interval of pre-order
[postL,postR] is current sequence interval of post-order
*/
void build(int preL,int preR,int postL,int postR){
    if(preL>=preR){
        return;
    }
    int fa=preL;
    //前序遍歷的第一個為根節點,第二個為子樹的根節點,可能是左孩子也可能是右孩子
    int val=preOrder[preL+1];
    int postIdx;
    for(int i=postL;i<postR;i++){
        if(val==postOrder[i]){
            postIdx=i; //val在后序遍歷中的索引
            break;
        }
    }
    int num=postIdx-postL; //以val為根節點的子樹節點個數
    //即以val為根節點的子樹只有一棵孩子,那么既可以為左孩子也可以為右孩子,所以不唯一
    if(preR-preL-1==num){
        isUnique=false;
    }
    node[fa].left=preL+1;  //不唯一的話,看做左孩子
    build(preL+1,preL+num+1,postL,postIdx);
    //如果以preL+1為根節點的子樹的節點個數小於fa的所有子樹節點的個數,說明fa還有右孩子
    if(preR-preL-1>num){
        node[fa].right=preL+num+2;
        build(preL+num+2,preR,postIdx+1,postR-1);
    }
}

bool first=true;
void inOrder(int root){
    if(root==-1){
        return;
    }
    inOrder(node[root].left);
    if(first){
        first=false;
        printf("%d",preOrder[root]);
    }
    else
        printf(" %d",preOrder[root]);
    inOrder(node[root].right);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&preOrder[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&postOrder[i]);
    build(1,n,1,n);
    if(isUnique)
        printf("Yes\n");
    else
        printf("No\n");
    inOrder(1);
    printf("\n");  //否則格式錯誤
    return 0;
}
View Code

 


免責聲明!

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



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