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

翻转二叉树:

若树为空树,那么返回;

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

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

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

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

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

#include 
#include 
using namespace std;

vector 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 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

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

#include 
#include 
#include 

using namespace std;
vector 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

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

#include 
#include 
#include 
using namespace std;
const int N = 60;
vector pre,in_,layer;
struct binaryTree{
    int left;
    int right;
}nodes[N];
int isleft[N];
int buildTree(vector 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 leftTree;
    vector rightTree;
    for (int i=1;i

最近公共祖先

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;
    }

你可能感兴趣的:(C++刷题,算法,数据结构)