由前序遍歷和中序遍歷重建二叉樹

思路:

  1. 根據前序遍歷序列找到根節點的值
  2. 在中序遍歷序列中找到根節點的位置
  3. 找到左子樹根節點(中序遍歷中根結點的前一個位置,如果存在的話,就是左子樹的根結點)
  4. 找到右子樹根節點(中序遍歷中根結點的後一個位置,如果存在的話,就是右子樹的根結點)
  5. 遞歸地重建子樹(使用左子樹的前序、中序序列構建左子樹;使用右子樹的前序、中序序列構建右子樹)

例如下面這張圖(出自《劍指offer》):

這裏寫圖片描述

下面是代碼:

/* 由前序遍歷序列和中序遍歷序列重建二叉樹 */
#include <iostream>
#include <cstdlib>
using namespace std;

struct Node
{
    int val;
    Node* left;
    Node* right;
};

Node* construct(int* preOrder, int* inOrder, int length)
{
    Node* root = (Node*)malloc(sizeof(Node)); // 爲子樹的根節點分配空間(我們把整棵樹的根節點也暫且當作子樹)
    int rootVal = preOrder[0]; // 子樹的根結的值一定保存在前序遍歷序列的第一個位置
    root->val = rootVal; // 設置子樹根結點的值
    root->left = root->right = nullptr; // 先將左右子樹均設置爲空指針,避免出現野指針

    // 如果前序遍歷和中序遍歷序列的長度爲1,說明只有一個結點,直接作爲葉結點返回即可
    if (1 == length) return root; 

    // rootIn用於保存當前子樹的根節點在中序遍歷序列中的位置
    // rootIn-1(如果存在的話)就是當前子樹的左子樹的根節點
    // rootIn+1(如果存在的話)就是當前子樹的右子樹的根節點
    int* rootIn = inOrder;
    while (rootIn <= inOrder && *rootIn != rootVal) // 查找當前子樹的根節點在中序遍歷序列中的位置
        ++rootIn;

    int lenL = rootIn - inOrder; // 左子樹的長度
    int lenR = length - lenL - 1; // 右子樹的長度
    if (lenL > 0) // 如果當前子樹的左子樹存在,遞歸的構建左子樹
        root->left = construct(preOrder + 1, inOrder, lenL);
    if (lenR > 0) // 如果當前子樹的右子樹存在,遞歸的構建左子樹
        root->right = construct(preOrder + lenL + 1, rootIn + 1, lenR);

    return root; // 返回當前子樹的根節點
}

void tranverse(Node* root) // 前序遍歷重建得到的二叉樹
{
    if (nullptr == root) return;
    cout << root->val << ' ';
    tranverse(root->left);
    tranverse(root->right);
}

int main()
{
    int preOrderSeq[] = {1, 2, 4, 7, 3, 5, 6, 8};
    int inOrderSeq[] = {4, 7, 2, 1, 5, 3, 8, 6};
    const int length = 8;
    Node* root = construct(preOrderSeq, inOrderSeq, length);
    tranverse(root);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章