翻转二叉树、还原二叉树、最近公共祖先

翻转二叉树:

若树为空树,那么返回;

若不为空,则先递归翻转左右子树,然后再将左右子树的结点互换。

void revert(int root){
    if (root == -1){
        return;
    }
    revert(nodes[root].left);
    revert(nodes[root].right);
    swap(nodes[root].left,nodes[root].right);
}

先序中序还原二叉树、后序中序还原二叉树、层序中序还原二叉树

两个序列一个提供根结点,另一个用来划分左右子树

以先序中序还原二叉树为例,先序的第一个元素为该树的根结点,通过该根结点的编号,便可以将中序和先序的元素划分左右子树。左右子树的根结点就是该树的左右结点,同时该树的根结点又有可能是其父亲结点的左右孩子。

#include <cstdio>
#include <vector>
using namespace std;

vector<int> pre,in_;
const int N = 55;
struct binaryTree{
    int left;
    int right;
}nodes[N];
int buildTree(int preL,int preR,int inL,int inR){
    /*
    整个思路很简单,通过先序序列找出该子树的根结点
    然后根据中序序列通过根结点root再将子树分为左子树和右子树。
    返回根结点
    */
    if (preL > preR)return -1;

    int root = pre[preL];
    int rootindexofin;//找到root在中序序列中的位置

    for (int i=inL;i<=inR;i++){
        if (in_[i] == root){
            rootindexofin = i;
            break;
        }
    }
    // root的左子节点就是其左子树的根结点,反之其也可能是其父亲结点的左子节点/右子节点
    int countof_LeftTree = rootindexofin - inL;//其左子树的结点数
    nodes[root].left = buildTree(preL+1,preL+countof_LeftTree,inL,rootindexofin-1);
    nodes[root].right = buildTree(preL+countof_LeftTree+1,preR,rootindexofin+1,inR);
    return root;
}

vector<int> post;
void postorder(int root){
    if (root==-1)return;

    postorder(nodes[root].left);
    postorder(nodes[root].right);
    post.push_back(root);
}
int main(){
    int n;
    scanf("%d",&n);
    for (int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        pre.push_back(temp);
    }
    for (int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        in_.push_back(temp);
    }
    int root = buildTree(0,pre.size()-1,0,in_.size()-1);
    postorder(root);
    for (int i=0;i<post.size();i++){
        if (i==post.size()-1)printf("%d",post[i]);
        else printf("%d ",post[i]);
    }
    return 0;
}

后序中序还原二叉树,后序序列,那么每个根结点就是其最后一个元素,后面的思路相同。

#include <cstdio>
#include <vector>
#include <queue>

using namespace std;
vector<int> in_,pre,post;

const int N = 60;
struct binaryTree{
    int left;
    int right;
}nodes[N];
int buildTree(int postL,int postR,int inL,int inR){
    if (postL>postR)return -1;

    int root = post[postR];
    int rootindexofin;
    for (int i=inL;i<=inR;i++){
        if (in_[i] == root){
            rootindexofin = i;
            break;
        }
    }
    int countleftTree = rootindexofin - inL;
    nodes[root].left = buildTree(postL,postL+countleftTree-1,inL,rootindexofin-1);
    nodes[root].right = buildTree(postL+countleftTree,postR-1,rootindexofin+1,inR);
    return root;
}
void preorder(int root){
    if (root == -1)return;
    pre.push_back(root);
    preorder(nodes[root].left);
    preorder(nodes[root].right);
}
int main(){
    int n;
    scanf("%d",&n);
    for (int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        post.push_back(temp);
    }
    for (int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        in_.push_back(temp);
    }
    int root = buildTree(0,post.size()-1,0,in_.size()-1);
    preorder(root);
    for (int i=0;i<pre.size();i++){
        if (i == pre.size()-1)printf("%d",pre[i]);
        else printf("%d ",pre[i]);
    }
    return 0;
}

 层序中序还原二叉树:思路一样,层序序列无法像前面两个可以简单地分开左右子树的元素,因而需要重新筛检左右子树的元素,重新使用vector进行组合,按照层序序列的顺序筛完,第一个元素总是该树的根结点。

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int N = 60;
vector<int > pre,in_,layer;
struct binaryTree{
    int left;
    int right;
}nodes[N];
int isleft[N];
int buildTree(vector<int> layer,int inL,int inR){
    memset(isleft,0,sizeof isleft);
    if (layer.size()==0)return -1;
    int root = layer[0];
    int rootindexofin;
    for (int i=inL;i<=inR;i++){
        if (in_[i] == root){
            rootindexofin = i;
            break;
        }else {
            isleft[in_[i]] = 1;
        }
    }
    vector<int> leftTree;
    vector<int> rightTree;
    for (int i=1;i<layer.size();i++){
        if (isleft[layer[i]] == 1)leftTree.push_back(layer[i]);
        else rightTree.push_back(layer[i]);
    }
    nodes[root].left = buildTree(leftTree,inL,rootindexofin-1);
    nodes[root].right = buildTree(rightTree,rootindexofin+1,inR);
    return root;
}
void preorder(int root){
    if (root == -1)return;
    pre.push_back(root);
    preorder(nodes[root].left);
    preorder(nodes[root].right);
}
int main(){
    int n;
    scanf("%d",&n);
    for (int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        layer.push_back(temp);
    }
    for (int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        in_.push_back(temp);
    }
    int root = buildTree(layer,0,in_.size()-1);
    preorder(root);
    for (int i=0;i<pre.size();i++){
        if (i==pre.size()-1)printf("%d",pre[i]);
        else printf("%d ",pre[i]);
    }
    return 0;

}

最近公共祖先

1.终止条件:

    if (root == -1)return -1;//此时root == -1已经为叶子结点,未找到 p和q,返回-1
    // 找到p和q返回p和q
    if (root == p) return p;
    if (root == q) return q;
    

左右地递归:返回左右子树的结果:

    int left = LCA(nodes[root].left,p,q);
    int right = LCA(nodes[root].right,p,q);

接下来的判断才是重要的:

我们现在处在root这个树这里,根据左右子树寻找的结果来返回最近的公共祖先

现在返回的值要么是-1(表示未寻找到p和q)和截止至root这个位置的最近公共祖先的结点的数值。

1. p,q在root分别存在于root的左右子树中(异侧)——>root即为最近祖先节点

if (left != -1 && right != -1){
        return root;
}

2. p, q均在root的左侧——>p/q即为最近祖先节点

那么right == 1而left !=-1,由于是最近公共结点,此时的left值便是最近。

else if (left != -1){
        return left;
    }

3. p, q均在root的右侧——>同理

else if (right != -1){
        return right;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值