1. 程式人生 > >二叉樹重建

二叉樹重建

定理: 已知前序和中序遍歷,可以確定一棵二叉樹。已知中序和後序遍歷,可以確定一棵二叉樹。但是,已知前序和後序遍歷,不能確定一棵二叉樹。換句話說,已知中序遍歷和前序遍歷或後序遍歷能夠確定一顆二叉樹。

題目描述

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建出如圖所示的二叉樹並輸出它的頭結點。 在這裡插入圖片描述

分析及實現:

根據二叉樹前序遍歷的特點(根-左-右),每次讀取的第一個值一定是根節點,這樣我們可以在中序遍歷的序列中找到當前的根節點的位置。 根據中序遍歷的特點(左-根-右),當確定了一個根節點後,其左邊序列就是這個根節點的左子樹,右邊序列就是其右子樹。 在這裡插入圖片描述

如此看來,我們每次都需要在前序遍歷中找根節點並建立一個根節點,然後在中序遍歷中確定根節點位置,並確定當前根節點的左右子樹,然後以同樣的方法去構建左右子樹。這整個過程其實是一個遞迴的過程。 程式碼實現 在實現的時候,我們需要每次記錄根節點的左右序列值,以便下一次找根節點構建樹,因此這裡使用vector來記錄

//根據前序遍歷和中序遍歷重建二叉樹
Node* RebuildTree(vector<int> prev, vector<int> vin)
{
    if (prev.empty() || vin.empty())
        return NULL;

    //在前序遍歷中prev中找根節點,並確定其在vin的位置
    size_t index = 0;
    for (; index<vin.size(); index++)
    {
        if (vin[index] == prev[0])
            break;
    }
    //已經找到根節點,並構造根節點
    Node* root = new Node(prev[0]);
    //Print(root);
    //根據中序遍歷將根節點左右兩側一分為二,根節點的左側為左子樹,右側為右子樹
    vector<int> prev_left,prev_right;
    vector<int> vin_left,vin_right;
    //先將前序、中序中根節點的左右子樹記錄下來
    for (size_t j=0; j<index; j++)
    {
        prev_left.push_back(prev[j+1]);
        vin_left.push_back(vin[j]);
    }
    for (size_t j=index+1; j<vin.size(); j++)
    {
        prev_right.push_back(prev[j]);
        vin_right.push_back(vin[j]);
    }
    //遞迴構造左右子樹
    root->_left = RebuildTree(prev_left,vin_left);
    root->_right = RebuildTree(prev_right,vin_right);

    return root;
}