剑指offer - 重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建二叉树。假设输入的前序遍历和中序遍历的结果中都不包含重复的数字。

例如:输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建如下图的二叉树并输出它的头节点。

182347578161183.jpg

二叉树节点的定义如下

struct BinaryTreeNode {
    int m_nValue;
    BinaryTreeNode *m_pLeft;
    BinaryTreeNode *m_pRight;
};

二叉树的遍历流程

通常树有如下几种遍历方式:

前序遍历:先访问根结点,再访问左子结点,最后访问右子结点。
中序遍历:先访问左子结点,再访问根结点,最后访问右子结点。
后序遍历:先访问左子结点,再访问右子结点,最后访问根结点。

jlIAfhlcL3.png

注意:

前序和后序的遍历序列的无法唯一确定一颗二叉树。

分析

在二叉树的前序遍历中,第一个数字总是树的根节点的值,但在中序遍历序列中,根节点的值在序列的中间,左子树的节点的值位于根节点的值的左边,而右子树的节点的值位于根节点的值的右边。因此我们需要扫描中序遍历序列,才能找到根节点的值

前序遍历序列的第一个数字1就是根节点的值。扫描中序遍历序列,就能确定根节点的值的位置。根据中序遍历的特点,在根节点的值1前面的3个数字都是左子树节点的值,位于1后面的数字都是右子树节点的值。

由于在中序遍历序列中,有3个数字是左子树节点的值,因此左子树共有3个左子节点。同样,在前序遍历序列中,根节点后面的3个数字就是3个左子树节点的值,再后面的所有数字都是右子树节点的值,这样我们就在前序遍历和中序遍历中分别找到了左、右子树对应的子序列。

182352237859627.jpg

既然我们已经分别找到了左、右子树的前序遍历序列和中序遍历序列,我们可以用同样的方法分别构建左、右子树。

思路总结:

先根据前序遍历序列的第一个数字创建根结点,接下来在中序遍历序列中找到根结点的位置,这样就能确定左、右子树结点的数量。在前序遍历和中序遍历的序列中划分了左、右子树结点的值之后,就可以递归地去分别构建它的左右子树。

递归实现(C++)

// 前向声明
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);

BinaryTreeNode* Construct(int *preorder, int *inorder, int length)
{
    // 确保输入的数组是有值的,处理为空的情况
    if (preorder == nullptr || inorder == nullptr || length <= 0)
        return nullptr;

    return ConstructCore(preorder, preorder + length - 1, inorder, inorder + length - 1);

}

// startPreorder 开始前序遍历指针  startInorder 开始的中序遍历指针
BinaryTreeNode* ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder )
{
    // 前序遍历的第一个值就是根节点
    int rootValue = startPreorder[0];

    // 创建一个新的二叉树
    BinaryTreeNode *root = new BinaryTreeNode();
    // 值为根节点的值
    root->m_nValue = rootValue;
    // 左右子树目前为空
    root->m_pLeft = root->m_pRight = nullptr;

    // 处理只有根节点的情况
    if (startPreorder == endPreorder) { // 如果前序遍历序列的开始指针等于结尾指针
        if (startInorder == endInorder) // 中序遍历序列的开始指针等于结束指针,那么只有根节点,直接返回
            return root;
        else
        {
            logic_error ex("Invalid Input");
            throw exception(ex);
        }
    }

    // 在中序遍历序列中找到根节点的值
    int *rootInorder = startInorder;
    while (rootInorder<=endInorder && *rootInorder != rootValue)
        ++rootInorder;

    // 中序遍历结束,找不到根节点,输入中序序列错误,抛出异常
    if (rootInorder == endInorder && *rootInorder != rootValue)
    {
        logic_error ex("Invalid Input");
        throw exception(ex);
    }

    // 找到了根节点,就可以确认左子树和右子树的范围
    int leftLength = rootInorder - startInorder;
    int *leftPreorderEnd = startPreorder + leftLength;
    if (leftLength > 0)
    {
        // 构建左子树
        root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
    }
    if (leftLength < endPreorder - startPreorder)
    {
        // 构建右子树
        root->m_pRight = ConstructCore(leftPreorderEnd + 1, endInorder, rootInorder + 1, endInorder);
    }
    return root;
}

参考

数据结构:关于重建二叉树的三种思路
二叉树怎样序列化才能重建

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容