重建二叉树&&二叉树的下一个节点

重建二叉树&&二叉树的下一个节点

重建二叉树

题目

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

typedef struct BinaryTreeNode{
    int value;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
    BinaryTreeNode():value(0),left(NULL),right(NULL){};
}BinaryTreeNode;
  1. 前序序列遍历确定root
  2. 由root去将中序遍历序列一分为二,左边leftLength个,右边rightLength个
  3. 则左子树的前序遍历序列,中序遍历序列确定下来的;右子树的前序遍历序列,中序遍历序列也确定下来了。
  4. 递归

在这里插入图片描述
代码示例(不太推荐这种写法,直接看下面的示例)
-------------------------------------------------------------------------------来自《剑指offer》

#include<iostream>
#include<exception>
#include<stdexcept>
using namespace std;

typedef struct BinaryTreeNode{
    int value;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
    BinaryTreeNode():value(0),left(NULL),right(NULL){};
}BinaryTreeNode;

//声明
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){
    int rootValue=startPreorder[0];
    BinaryTreeNode* root=new BinaryTreeNode();
    root->value=rootValue;

    //base case
    if(startPreorder==endPreorder){
        //仅有一个节点
        if(startInorder==endInorder && *startPreorder==*startInorder)
            return root;
        else
            //注意参考https://stackoverflow.com/questions/28640553/exception-class-with-a-char-constructor
            //windows的msvc编译器中可以使用throw std::exception("Invalid input")
            //gcc编译器中,不能这样throw std::exception("Invalid input")
            throw std::logic_error("Invalid input");
    }
    //找到rootValue在Inorder序列中的位置
    int *rootInorder=startInorder;
    while(rootInorder<=endInorder&&*rootInorder!=rootValue)
        rootInorder++;
    if(rootInorder>endInorder)
        throw std::logic_error("Invalid input");
    //左子树序列的长度
    int leftLength=rootInorder-startInorder;
    int *leftPreorderEnd=startPreorder+leftLength;
    if(leftLength>0)//左子树序列有值
    {
         root->left=ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder-1);
    }
    if(leftLength<endPreorder-startPreorder){//右子树序列有值
        root->right=ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);
    }
    return root;
}

//后序遍历二叉树作为测试
void  postOrder(BinaryTreeNode* root){
    if(root==NULL) return ;
    postOrder(root->left);
    postOrder(root->right);
    cout<<root->value<<"-> ";
}

int main(){
    //动态数组初始化
    int* preOrder=new int[8]{1,2,4,7,3,5,8,6};
    int* InOrder=new int[8]{1,2,4,7,3,5,8,6};

    BinaryTreeNode* root=Construct(preOrder,InOrder,8);
    postOrder(root);
    
    delete[] preOrder;
    delete[] InOrder;

    system("pause");
    return 0;
}

上面是剑指offer的代码示例,感觉不太好,下面推荐的是leetcode的代码示例
105. 从前序与中序遍历序列构造二叉树

思路:
前序:根 左子树节点元素 右子树节点元素
中序:左子树节点元素 根 右子树节点元素
1.先由前序确定根,然后由根元素去中序序列中查找,进而将中序序列分成两半,左边leftNums个节点,右边rightNums个节点
2.然后开始递归
注意:这里由根元素去中序序列中查找,可以中unordered_map优化,先把中序的值和对应下标存在unordered_map中

#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;

typedef struct BinaryTreeNode{
    int value;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
    BinaryTreeNode(int val):value(val),left(NULL),right(NULL){};
}BinaryTreeNode;

BinaryTreeNode* constructBTCore(vector<int>& preOrder,vector<int>& inOrder,int preLeft,int preRight,int inLeft,int inRight,unordered_map<int,int>& mp){
    if(preRight<preLeft||inRight<inLeft) return nullptr;
    if(preRight-preLeft!=inRight-inLeft) return nullptr;

    //建立根节点
    BinaryTreeNode* root=new BinaryTreeNode(preOrder[preLeft]);
    //找到根在中序序列中的位置
    int leftNums=mp[preOrder[preLeft]]-inLeft;
    //重建左边
    root->left=constructBTCore(preOrder,inOrder,preLeft+1,preLeft+leftNums,inLeft,inLeft+leftNums-1,mp);
    //重建右边
    root->right=constructBTCore(preOrder,inOrder,preLeft+leftNums+1,preRight,mp[preOrder[preLeft]]+1,inRight,mp);

    return root;
}

BinaryTreeNode* constructBT(vector<int>& preOrder,vector<int>& inOrder){
    if(preOrder.size()!=inOrder.size()) return nullptr;
    //遍历inOrder,保存到mp
    unordered_map<int,int> mp;
    for(int i=0;i<inOrder.size();i++){
        mp[inOrder[i]]=i;
    }
    return constructBTCore(preOrder,inOrder,0,preOrder.size()-1,0,inOrder.size()-1,mp);
}

二叉树的下一个节点

题目

给定一棵二叉树和其中的一个节点,如何找出中序遍历序列的下一个节点?树中的节点除了有两个分别指向左、右子节点的指针,还有一个指向父节点的指针。
在这里插入图片描述

  1. 如果一个节点有右子树,则它的下一个节点就是其右子树的最左节点
  2. 如果一个节点没有右子树,且它是它父亲节点的左子节点,则它的下一个节点就是其父亲节点
  3. 如果一个节点没有右子树,且它是它父亲节点的右子节点,则我们可以沿着指向父亲节点的指针一直向上遍历,直到找到一个是它父亲节点左子节点的节点。如果这样的节点存在,那么这个节点的父亲节点就是我们要找的下一个节点。
#include<iostream>
#include<exception>
#include<stdexcept>
using namespace std;

typedef struct BinaryTreeNode{
    int value;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
    BinaryTreeNode* parent;
    BinaryTreeNode():value(0),left(NULL),right(NULL),parent(NULL){};
}BinaryTreeNode;

/*
*1. 如果一个节点有右子树,则它的下一个节点就是其右子树的最左节点
*2. 如果一个节点没有右子树,且它是它父亲节点的左子节点,则它的下一个节点就是其父亲节点
*3. 如果一个节点没有右子树,且它是它父亲节点的右子节点,则我们可以沿着指向父亲节点的指针一直向上遍历,
*   直到找到一个是它父亲节点左子节点的节点。如果这样的节点存在,那么这个节点的父亲节点就是我们要找的下一个节点。
*/
BinaryTreeNode* GetNextNode(BinaryTreeNode* pNode){
    if(pNode==NULL) return NULL;

    BinaryTreeNode* NextNode=NULL;
    if(pNode->right!=NULL) {
        NextNode=pNode->right;
        while(NextNode->left!=NULL)
            NextNode=NextNode->left;
        return NextNode;
    }
    else if(pNode->parent!=NULL){
        if(pNode->parent->left==pNode)
            return pNode->parent;
        else{
            BinaryTreeNode* CurrentNode=pNode;
            while(CurrentNode->parent!=NULL && CurrentNode->parent->right==CurrentNode)
                CurrentNode=CurrentNode->parent;
            if(CurrentNode->parent!=NULL)//说明存在下一个节点
                return CurrentNode->parent;
        }
    }
    //说明已回溯到根节点,也没有找到下一个节点。
    return NULL;
}

int main(){
    BinaryTreeNode array[5];//对象数组,默认初始化
    for(int i=0;i<5;i++){
        array[i].value=i;
    }
    array[2].parent=NULL;
    array[2].left=&array[1];
    array[2].right=&array[4];
    
    array[1].parent=&array[2];
    array[1].left=&array[0];
    array[1].right=NULL;

    array[0].parent=&array[1];
    array[0].left=NULL;
    array[0].right=NULL;

    array[4].parent=&array[2];
    array[4].left=&array[3];
    array[4].right=NULL;

    array[3].parent=&array[4];
    array[3].left=NULL;
    array[3].right=NULL;

    //测试
    for(int j=0;j<5;j++){
        BinaryTreeNode* temp=GetNextNode(&array[j]);
        if(temp!=NULL)
             cout<<"array["<<j<<"]"<<"->NextNode->value="<<temp->value<<endl;
        else
            cout<<"array["<<j<<"]"<<"->NextNode==NULL"<<endl;
    }

    system("pause");
    return 0;
}

测试时建立的二叉树如下图:
在这里插入图片描述
输出结果如下:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值