每日一题(12)

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针

分析:

             1                          1
            / \                        /
           2   3                      2
          /   / \                      \
         4   5   6                      3  
            图1                        图2
  1. 如果pNode为空,则不可能有后续结点,直接返回;
  2. 如果pNode的右子树存在,中序次序下pNode的下一个结点刚好为其右子树中最左侧结点
    比如pNode在根节点的位置,该节点中序遍历下的第一个结点为5
    因此如果pNode的右子树存在,实际是求该节点右子树中最左侧结点
  3. 如果该结点的右子树不存在,中序下第一个结点:
    可能为其双亲,比如图1中的4结点,其中序下一个结点为2
    可能需要一直向上找双亲,比如图2中的3结点,其中序下的第一个结点为1
    综合两种结果,相当就是检测parent(pNode的双亲)右是否为pNode,如果是继续向上找,否则pNode的下一个结点找到pNode不是其双亲的右孩子为止
/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {

    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode==NULL)
            return NULL;
         // 如果pNode的右子树存在,找其右子树中最左侧结点
        if(pNode->right)
        {
            // 找到右子树中最左边结点
            pNode=pNode->right;
            while(pNode->left)
                pNode=pNode->left;
        }
        else{
            // 如果pNode的右子树不存在
            // 可能需要一直向上找其双亲,直到pNode不是其双亲的右孩子为止
            TreeLinkNode *parent=pNode->next;
            while(parent){
                if(parent->right!=pNode)
                    break;
                pNode=parent;
                parent=pNode->next;
            }
            // 最终找到结点为其双亲
            pNode=parent;
        }
        return pNode;
    }
};

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回

分析:

  1. 熟悉二叉树前序&中序遍历规则
    前序遍历规则:遍历根节点—->遍历根节点的左子树—->遍历根节点的右子树
    中序遍历规则:遍历根节点左子树—->遍历根的节点—->遍历根节点的右子树

  2. 前序:1 2 4 3 5 6 中序:4 2 1 5 3 6
    从遍历规则可知:前序遍历结果:根节点一定是遍历的第一个结点
    中序遍历结果:根节点一定在左子树之后右子树之前遍历
    因此,可以从前序遍历结果中找到二叉树的根,从中序遍历结果中找到二叉树的左右子树

  3. 思路
    a. 取前序遍历一个元素,即根节点中数据
    b. 在中序遍历结果中找到a中所取元素的位置,按照该位置将序列分为左右两部分,即根的左右子树
    c. 创建二叉树的根节点(数据为a中所取数据)
    按照b中所划分区间:递归创建根左子树

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode *_reConstructBinaryTree(const vector<int> &pre,size_t &preIndex,
                                     const vector<int>&vin,size_t left,size_t right)
    {
        if(left>=right || preIndex>=pre.size())
            return NULL;

        // 在中序遍历结果中找二叉树根的位置
        size_t rootIndex=left;
        while(rootIndex<right){
            if(vin[rootIndex]==pre[preIndex])
                break;
            ++rootIndex;
        }

         // 还原二叉树根节点
        TreeNode *pRoot=new TreeNode(pre[preIndex]);

         // 如果左区间存在还原根的左子树
        if(left<rootIndex){
            pRoot->left=_reConstructBinaryTree(pre,++preIndex,vin,left,rootIndex);
        }

          // 如果右区间存在,还原根的右子树
        if(rootIndex+1<right){
            pRoot->right=_reConstructBinaryTree(pre,++preIndex,vin,++rootIndex,right);
        }

        return pRoot;
    }
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.size()!=vin.size())
            return NULL;
        size_t preIndex=0;
        return _reConstructBinaryTree(pre,preIndex,vin,0,pre.size());
    }
};

猜你喜欢

转载自blog.csdn.net/sifanchao/article/details/81842769