中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

用一棵二叉樹的前序遍歷結果和中序遍歷結果還原這棵二叉樹——6

發布時間:2020-04-01 14:45:32 來源:網絡 閱讀:1168 作者:給我個bit位 欄目:編程語言

    輸入某二叉樹的前序遍歷和中序遍歷的結果,重建出這棵二叉樹,假設輸入的前序遍歷和中序遍歷的結果中都不含重復的數字。例如,輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建出這棵滿足前序遍歷和中序遍歷的二叉樹并輸出它的頭結點。

    對一棵二叉樹前序遍歷的順序是“根結點->左結點->右結點”,而中序遍歷的順序是“左結點->根節點->右結點”,因此,一般的思路都是醬紫的:

  1. 前序遍歷列表中,第一個數據肯定是根節點,而中序遍歷列表中,第一個數據肯定是樹的最左結點,這樣就可以得知,在前序遍歷中,從根結點到最左結點一定是樹的最左分支,也就是“1->2->4”;

  2. 接下來,在中序遍歷中,訪問完最左結點4之后因為其左結點為NULL要訪問的就是4的右分支的最左結點了,為7,而在前序遍歷中訪問到最左結點之后就要訪問右結點,發現也為7,說明7就是最左結點4的右分支上的最左結點,也就是只有7一個右結點;

  3. 然后,在中序遍歷中訪問完最左結點也就是以4為根節點子樹之后,就要回到4結點的父節點了,也就是2,再往下訪問是根節點1,也就是2并沒有右結點;

  4. 至此會發現1為根節點的左子樹已經全部訪問完了;

 

    上面沒有再繼續往下分析,是因為會發現,上面說的一堆雖然能把樹給重建出來,但是很繁瑣,邏輯上有關聯卻難以疏通個條理出來,因此要想轉換為代碼來實現想必又是要大費周折;

    為什么分析到第四點就停下了,是因為第四點的式轉換新思路的一個起點:

  1. 首先前面第一點中加粗的字體肯定是沒有問題的,前序遍歷中第一個數據一定是樹的根結點

  2. 再結合第四點,在中序遍歷中找到這個根結點,會發現以1為根結點前面的數據都是1的左子樹,有三個結點,那么在前序遍歷中1后面的三個結點都是屬于左子樹的;因此,在1后面的數據肯定也都是在1的右子樹上,有四個結點;

  3. 接下來看在前序遍歷中跟在1后面的數據2是在1的左邊還是右邊,在左邊就是1的左結點,在右邊就是1的右結點;

  4. 然后按照前序遍歷列表中的順序將2看為新的根結點,那么在它左邊的數據就是它左子樹上的,右邊的數據就是右子樹上的,當然是截止到前一個根結點1為止;然后就再次循環從上一步開始;


可畫圖如下:

用一棵二叉樹的前序遍歷結果和中序遍歷結果還原這棵二叉樹——6


    是不是會發現第二次的分析比第一次要簡單明了多了?而且邏輯上有重復性,這樣的分析用代碼實現起來會比較容易,可以用遞歸來實現:

#include <iostream>
#include <assert.h>
using namespace std;

typedef int data_type;

//首先定義一個樹結點的結構體并實現構造函數
struct BinaryTreeNode
{
    data_type _data;
    BinaryTreeNode* _Lnode;
    BinaryTreeNode* _Rnode;

    BinaryTreeNode(data_type data)
        :_data(data)
        ,_Lnode(NULL)
        ,_Rnode(NULL)
    {}  
};

//重建二叉樹,參數為兩個遍歷列表,樹結點的個數,還有遞歸所需要知道子樹的范圍
BinaryTreeNode* RebuildBinaryTree(const data_type* prevlist, const data_type *inlist, const size_t num, size_t head, size_t tail)
{
    assert(prevlist && inlist && num);  //判斷參數有效性
    //前序遍歷列表中第一個結點一定是樹的根結點
    BinaryTreeNode *root = new BinaryTreeNode(*prevlist);

    size_t root_index;
    //在中序遍歷列表中找出根結點
    for(root_index = 0; root_index < num; ++root_index)
    {   
        if(inlist[root_index] == *prevlist)
            break;
    }   
    if(inlist[root_index] != *prevlist)  //檢查給出的序列是否為有效的遍歷序列
    {   
        cout<<"Invalid parameter..."<<endl;
        exit(0);
    }   

    //當結點個數大于0的時候才表示會有子結點,否則為已經初始化過的NULL
    //傳遞首尾范圍的時候,是不包括根結點的,因此要注意
    size_t left_node_num = root_index - head;//根結點左邊的結點個數
    if(left_node_num > 0)
        root->_Lnode = RebuildBinaryTree(prevlist+1, inlist, num, head, root_index-1);

    size_t right_node_num = tail - root_index;//根結點右邊的結點個數
    if(right_node_num > 0)
        root->_Rnode = RebuildBinaryTree(prevlist+left_node_num+1, inlist, num, root_index+1, tail);

    return root;
}

//前序遍歷檢查二叉樹是否正確重建
void PreOrder(BinaryTreeNode *root)
{
    if(root != NULL)
    {
        cout<<root->_data<<"->";
        PreOrder(root->_Lnode);
        PreOrder(root->_Rnode);
    }
}

int main()
{
    data_type PrevOrderList[] = {1, 2, 4, 7, 3, 5, 6, 8};
    data_type InOrderList[] = {4, 7, 2, 1, 5, 3, 8, 6};

    size_t node_num = sizeof(PrevOrderList)/sizeof(PrevOrderList[0]);
    //這里的首部和尾部的表示范圍都是在中序遍歷中
    size_t head = 0;
    size_t tail = node_num-1;
    BinaryTreeNode* root = RebuildBinaryTree(PrevOrderList, InOrderList, node_num, head, tail);

    cout<<"the root data: "<<root->_data<<endl;
    PreOrder(root);
    cout<<"NULL"<<endl;
    return 0;
}


運行程序:

用一棵二叉樹的前序遍歷結果和中序遍歷結果還原這棵二叉樹——6


因為只是檢查書是否重建好,用遞歸寫樹的先序遍歷,輸出發現和給定的先序遍歷序列一樣,則樹重建完成。


《完》

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

米易县| 和平区| 罗山县| 遂平县| 浦城县| 青川县| 鲜城| 壶关县| 广东省| 宜宾市| 桃园市| 浮山县| 六安市| 旌德县| 崇左市| 合山市| 安义县| 黑水县| 临颍县| 南华县| 从化市| 宁波市| 满城县| 奉节县| 体育| 牡丹江市| 云霄县| 水城县| 图木舒克市| 丹巴县| 专栏| 柯坪县| 祁门县| 溆浦县| 石屏县| 和田市| 张家口市| 临猗县| 梨树县| 永吉县| 兰坪|