《剑指offer》第六题(重要!重建二叉树)

文件一:main.cpp

// 面试题:重建二叉树
// 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输
// 入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,
// 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建出
// 图2.6所示的二叉树并输出它的头结点。

#include <iostream>
#include "BinaryTree.h"
using namespace std;

BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);

BinaryTreeNode* Construct(int* preorder, int* inorder, int length)
{
    if (preorder == NULL || inorder == NULL || length <= 0)//确认输入存在
        return NULL;

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

BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder,int* startInorder, int* endInorder)//注意传入的是地址
{
    // 前序遍历序列的第一个数字是根结点的值
    BinaryTreeNode* root = CreateBinaryTreeNode(startPreorder[0]);//建立根节点

    if (startPreorder == endPreorder)//如果这个树只有根节点
    {
        if (startInorder == endInorder && *startPreorder == *startInorder)
            return root;
        else                        //注意判断输入是否真的是对的
            throw exception("Invalid input.");
    }

    // 在中序遍历中找到根结点的值
    int* rootInorder = startInorder;
    while (rootInorder <= endInorder && *rootInorder != startPreorder[0])
        ++rootInorder;

    if (rootInorder == endInorder && *rootInorder != startPreorder[0])//如果中序遍历中没有根节点,就抛出异常
        throw exception("Invalid input.");

    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, endPreorder,rootInorder + 1, endInorder);
    }

    return root;
}

// ====================测试代码====================
void Test(const char* testName, int* preorder, int* inorder, int length)
{
    if (testName != NULL)
        cout << testName << " begins:\n";

    cout << "The preorder sequence is: ";
    for (int i = 0; i < length; ++i)
        cout << preorder[i];
    cout << endl;

    cout << "The inorder sequence is: ";
    for (int i = 0; i < length; ++i)
        cout << inorder[i];
    cout << endl;

    try
    {
        BinaryTreeNode* root = Construct(preorder, inorder, length);
        PrintTree(root);

        DestroyTree(root);
    }
    catch (exception& exception)
    {
        cout << "Invalid Input.\n";
    }
}

// 普通二叉树
//              1
//           /     //          2       3
//         /       / //        4       5   6
//         \         /
//          7       8
void Test1()
{
    const int length = 8;
    int preorder[length] = { 1, 2, 4, 7, 3, 5, 6, 8 };
    int inorder[length] = { 4, 7, 2, 1, 5, 3, 8, 6 };

    Test("Test1", preorder, inorder, length);
}

// 所有结点都没有右子结点
//            1
//           /
//          2
//         /
//        3
//       /
//      4
//     /
//    5
void Test2()
{
    const int length = 5;
    int preorder[length] = { 1, 2, 3, 4, 5 };
    int inorder[length] = { 5, 4, 3, 2, 1 };

    Test("Test2", preorder, inorder, length);
}

// 所有结点都没有左子结点
//            1
//             \
//              2
//               \
//                3
//                 //                  4
//                   //                    5
void Test3()
{
    const int length = 5;
    int preorder[length] = { 1, 2, 3, 4, 5 };
    int inorder[length] = { 1, 2, 3, 4, 5 };

    Test("Test3", preorder, inorder, length);
}

// 树中只有一个结点
void Test4()
{
    const int length = 1;
    int preorder[length] = { 1 };
    int inorder[length] = { 1 };

    Test("Test4", preorder, inorder, length);
}

// 完全二叉树
//              1
//           /     //          2       3
//         / \     / //        4   5   6   7
void Test5()
{
    const int length = 7;
    int preorder[length] = { 1, 2, 4, 5, 3, 6, 7 };
    int inorder[length] = { 4, 2, 5, 1, 6, 3, 7 };

    Test("Test5", preorder, inorder, length);
}

// 输入空指针
void Test6()
{
    Test("Test6", NULL, NULL, 0);
}

// 输入的两个序列不匹配
void Test7()
{
    const int length = 7;
    int preorder[length] = { 1, 2, 4, 5, 3, 6, 7 };
    int inorder[length] = { 4, 2, 8, 1, 6, 3, 7 };

    Test("Test7: for unmatched input", preorder, inorder, length);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();

    system("pause");
}

文件二:BinaryTree.h

#ifndef BINARY_TREE_H
#define BINARY_TREE_H

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

BinaryTreeNode* CreateBinaryTreeNode(int value);
void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight);
void PrintTreeNode(const BinaryTreeNode* pNode);
void PrintTree(const BinaryTreeNode* pRoot);
void DestroyTree(BinaryTreeNode* pRoot);

#endif

文件三:BinaryTree.cpp

#include <iostream>
#include "BinaryTree.h"
using namespace std;

BinaryTreeNode* CreateBinaryTreeNode(int value)//创建一个二叉树节点
{
    BinaryTreeNode* pNode = new BinaryTreeNode();
    pNode->m_nValue = value;
    pNode->m_pLeft = NULL;
    pNode->m_pRight = NULL;

    return pNode;
}

void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight)//将两个孩子连接到一个父节点
{
    if (pParent != NULL)
    {
        pParent->m_pLeft = pLeft;
        pParent->m_pRight = pRight;
    }
}

void PrintTreeNode(const BinaryTreeNode* pNode)//打印当前二叉树节点
{
    if (pNode != NULL)//判断该节点存在否
    {
        cout << "value of this node is:" << pNode->m_nValue << endl;//打印父节点

        if (pNode->m_pLeft != NULL)//打印左孩子节点
            cout << "value of its left child is:" << pNode->m_pLeft->m_nValue << endl;
        else
            cout << "left child is NULL.\n";

        if (pNode->m_pRight != NULL)//打印右孩子节点
            cout << "value of its right child is:" << pNode->m_pRight->m_nValue << endl;
        else
            cout << "right child is NULL.\n";
    }
    else
    {
        cout << "this node is nullptr.\n";
    }

    cout << endl;
}

void PrintTree(const BinaryTreeNode* pRoot)//打印整个树
{
    PrintTreeNode(pRoot);//打印根节点

    if (pRoot != NULL)//递归打印左右孩子节点,但是注意判断节点是否存在
    {
        if (pRoot->m_pLeft != NULL)
            PrintTree(pRoot->m_pLeft);

        if (pRoot->m_pRight != NULL)
            PrintTree(pRoot->m_pRight);
    }
}

void DestroyTree(BinaryTreeNode* pRoot)//删除整个树
{
    if (pRoot != NULL)
    {
        BinaryTreeNode* pLeft = pRoot->m_pLeft;
        BinaryTreeNode* pRight = pRoot->m_pRight;

        delete pRoot;
        pRoot = NULL;

        DestroyTree(pLeft);//递归调用该函数,分别把左右孩子节点作为父节点
        DestroyTree(pRight);
    }
}

原文地址:https://www.cnblogs.com/CJT-blog/p/10467058.html

时间: 2024-12-10 00:52:13

《剑指offer》第六题(重要!重建二叉树)的相关文章

剑指Offer(书):重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回. 分析:递归的本质就是将大问题不断分解为相同类型的小问题,直到找到一个出口为止.这里,根据前序和中序的性质找到1为根节点,那么就可以分解为2,4,7与4,7,2,即长度变短了.之后依次求解其他的. public TreeNode reConstructBin

剑指Offer——面试题7:重建二叉树

题目:输入某二叉树的前序遍历和中序遍历结果,重建该二叉树.(假设输入的前序和中序遍历结果中都不含重复数字) 1 #include "BinaryTree.h" 2 #include <stdexcept> 3 #include <iostream> 4 #include <cstdio> 5 #include <cstdlib> 6 7 BinaryTreeNode* ConstructCore(int* startPreorder, i

《剑指offer》刷题目录

<剑指offer>刷题目录 面试题03. 数组中重复的数字 面试题04. 二维数组中的查找 面试题05. 替换空格 面试题06. 从尾到头打印链表 面试题07. 重建二叉树 原文地址:https://www.cnblogs.com/qujingtongxiao/p/12652970.html

剑指Offer系列之题11~题15

目录 11.矩形覆盖 12.二进制中1的个数 13. 数值的整数次方 14.调整数组顺序使奇数位于偶数前面 15.链表中倒数第k个结点 11.矩形覆盖 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 比如n=3时,2*3的矩形块有3种覆盖方法: 斐波那契数列的应用 第一次竖着放一块类比为走一步,第一次横着放两块类比为走两步 代码与上面的斐波那契数列类题目类似,此处不再赘述:剑指Offer系列之题6~题10. 12.

《剑指Offer》附加题_用两个队列实现一个栈_C++版

在<剑指Offer>中,在栈和队列习题中,作者留下来一道题目供读者自己实现,即"用两个队列实现一个栈". 在计算机数据结构中,栈的特点是后进先出,即最后被压入(push)栈的元素会第一个被弹出(pop);队列的特点是先进先出,即第一个进入队列的元素将会被第一个弹出来.虽然栈和队列特点是针锋相对,但是两者却相互联系,可以互相转换. 在"用两个队列实现一个栈"问题中,我们用两个队列的压入和弹出来模拟栈的压入和弹出.我们通过画图的手段把抽象的问题形象化. 在上

浅谈《剑指offer》原题:求1+2+……+n

<剑指offer>上的一道原题,求1+2+--+n,要求不能使用乘除法,for.while.if.else.switch.case等关键字以及条件判断语句(a?b:c). 第一次看到这道题大约有一年的时间了,在霸笔网易的时候,当时我就晕了...心想这是神马东西,后来发现这是原题!!然后后悔自己没看过书了... <剑指offer>上给出了不错的解法,但是这里有个解法更巧妙,虽然技术含量不高,但是可以参考,这就是<程序员面试笔试宝典>中所给出的答案. 解法一:利用宏定义求解

剑指offer 面试14题

面试14题: 题目:剪绳子 题:给你一根长度为n的绳子,请把绳子剪成m段(m,n都是整数,且n>1,m>1),每段绳子的长度记为k[0],k[1],k[2],...,k[m].请问k[0]*k[1]*...*k[m]可能的最大乘积是多少?例如,当绳子的长度为8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积为18. 解题思路:基于动态规划和贪婪算法,详见剑指offer P96 解题代码: # -*- coding:utf-8 -*- class Solution: def Max

剑指offer 面试26题

面试26题: 题目:树的子结构 题:输入两棵二叉树A和B,判断B是不是A的子结构. 解题思路:递归,注意空指针的情况. 解题代码: # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def HasSubtree(self, pRoot1, pRoot2): # write co

剑指offer 面试29题

面试29题: 题目:顺时针打印矩阵(同LeetCode 螺旋矩阵打印) 题:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. 解题方法一:详见剑指offer 解题代码: # -*- coding:utf-8 -*- class Solution: # matrix类型为二维列表,需要返回

剑指offer 按之字形顺序打印二叉树

题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 思路: 1.有了之前层次遍历一行一行输出的经验,我们可以直接用一个变量记录行数,如果是奇数行,就将队列中的元素按顺序所有保存下来,如果是偶数行,就顺序保存到一个临时vector中,再逆序保存下来. 1 /* 2 struct TreeNode { 3 int val; 4 struct TreeNode *left; 5 struct Tre