从前序与中序遍历序列构建二叉树

LeetCode网站上的题目

https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

 

1.递归方法

//递归
class Solution
{
private:
    map<int,int>index;
    //函数意义:给定树在前序遍历和中序遍历时,所有节点的坐标区间,建立这棵树
    TreeNode* Creat_Tree_By_Pre_And_In(vector<int>&preorder,vector<int>inorder,int pre_left,int pre_right,int in_left,int in_right)
    {
        if(pre_left>pre_right)//递归终止条件,不使用=的原因是在树节点数为1的时候,也要建立节点
            return nullptr;
        //前序遍历的第一个节点就是根节点
        int root_pre_index=pre_left;
        //寻找根节点在中序遍历中的位置
        int root_in_index=index[preorder[root_pre_index]];
        //建立当前根节点
        TreeNode*root=new TreeNode(preorder[root_pre_index]);
        //计算当前根节点的左子树的节点数目
        int Left_Tree_Node_Nums=root_in_index-in_left;
        // 递归地构造左子树,并连接到根节点
        // 先序遍历中「从 左边界+1 开始的 Left_Tree_Node_Nums」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root->left=Creat_Tree_By_Pre_And_In(preorder,inorder,pre_left+1,pre_left+Left_Tree_Node_Nums,in_left,root_in_index-1);
        // 递归地构造右子树,并连接到根节点
        // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
        root->right=Creat_Tree_By_Pre_And_In(preorder,inorder,pre_left+Left_Tree_Node_Nums+1,pre_right,root_in_index+1,in_right);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
    {
        int i;
        int Tree_Nodes_Nums=inorder.size();
        for(i=0;i<Tree_Nodes_Nums;i++)
            index[inorder[i]]=i;
        return Creat_Tree_By_Pre_And_In(preorder,inorder,0,Tree_Nodes_Nums-1,0,Tree_Nodes_Nums-1);
    }
};

2.迭代方法

//迭代
/*1.我们用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(前序遍历的第一个节点),指针指向中序遍历的第一个节点;


2.我们依次枚举前序遍历中除了第一个节点以外的每个节点。如果 index 恰好指向栈顶节点,那么我们不断地弹出栈顶节点并向右移动 index,并将当前节点作为最后一个弹出的节点的右儿子;如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的左儿子;


3.无论是哪一种情况,我们最后都将当前的节点入栈。(因为所有节点都有可能是子树根节点)*/

class Solution
{
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
    {
        if (!preorder.size())
        {
            return nullptr;
        }
        TreeNode* root = new TreeNode(preorder[0]);//前序遍历的第一个就是树的根节点
        stack<TreeNode*> stk;
        stk.push(root);
        int inorderIndex = 0;//中序遍历数组的下标
        for (int i = 1; i < preorder.size(); ++i)
        {
            //顺序就是在前序遍历数组中遍历到当前节点时,以当前节点的前一个节点(即栈顶节点为根节点来进行树的建立)
            int preorderVal = preorder[i];//当前前序遍历的遍历值
            TreeNode* node = stk.top();//根节点
            if (node->val != inorder[inorderIndex])
            //这条语句就是在建立当前根节点的左节点
            {
                node->left = new TreeNode(preorderVal);
                stk.push(node->left);
            }
            //前序遍历构造的数组顺序是 根节点 左子树 右子树
            //中序遍历构造的数组顺序是 左子树 根节点 右子树
            //所以前序遍历的数组的最后一个元素比不可能是某个子树的根节点
            //else判断的就是当前序数组的值与中序数组的相同时,说明当前前序数组遍历根节点(即栈顶元素节点)没有左子树了
            //那么当前的数组遍历值就是入栈的那些左节点中的某一个的右节点
            //前序遍历与中序遍历在遇到一个右节点之前顺序是相反的,所以就不断弹出栈中元素,同时移动中序数组中的指针,
            //直到栈为空或者栈顶元素和中序数组指针指向的元素不相等了,说明上一个弹出的节点的右节点就是当前前序遍历的遍历值
            //再把当前前序遍历的遍历值入栈,可作为子树根节点
            else
            {
                while (!stk.empty() && stk.top()->val == inorder[inorderIndex])
                {
                    node = stk.top();
                    stk.pop();
                    ++inorderIndex;
                }
                node->right = new TreeNode(preorderVal);
                stk.push(node->right);
            }
        }
        return root;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值