c++ PTA二叉搜索树的最近公共祖先

给定一棵二叉搜索树的先序遍历序列,要求你找出任意两结点的最近公共祖先结点(简称 LCA)。

输入格式:
输入的第一行给出两个正整数:待查询的结点对数 M(≤ 1 000)和二叉搜索树中结点个数 N(≤ 10 000)。随后一行给出 N 个不同的整数,为二叉搜索树的先序遍历序列。最后 M 行,每行给出一对整数键值 U 和 V。所有键值都在整型int范围内。

输出格式:
对每一对给定的 U 和 V,如果找到 A 是它们的最近公共祖先结点的键值,则在一行中输出 LCA of U and V is A.。但如果 U 和 V 中的一个结点是另一个结点的祖先,则在一行中输出 X is an ancestor of Y.,其中 X 是那个祖先结点的键值,Y 是另一个键值。如果 二叉搜索树中找不到以 U 或 V 为键值的结点,则输出 ERROR: U is not found. 或者 ERROR: V is not found.,或者 ERROR: U and V are not found.。

在这里插入图片描述
思路:二叉搜索树的中序遍历即为将结点值按照非递减排序得到的结果,而根据输入的先序遍历和中序遍历我们就可以生成一个father数组,用以储存每个结点其父节点的序号(相对顺序序号)。
在寻找最近公共先祖节点的时候,利用两个栈,将待寻找的u、v自身以及其之上的所有祖先节点压入栈内,然后依次弹出两个栈顶的元素,直至找到不相同的两组数据,则上一个栈顶的元素即是最近公共先祖结点。

需要注意的点:
0.判断其中一个节点是否为另一个节点祖先结点的条件
1.输入数据并非是连续的从1到N的数,而是N个Int型的整数。因此father中存储的都是将输入数据按非递减排序得到的相对顺序标号。
2.u,v两个值相同返回其父节点即可。
3.输入u,v相同且为root根节点时返回格式是u是v的最近祖先结点。

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdio.h>

using namespace std;


int M,N,root;
queue<int> pro; //输入的先序遍历
vector<int> ino;  //中序遍历
int father[10006];
int findOrder(int a){
    for(int i = 1; i <= N; i++){
        if(a == ino[i]) {
            return i;
        }
    }
    return 0;
}
//构造父节点
void Build(int left, int right, int f){
    if(left > right) return;
    int t = pro.front(); //当前节点的值
    pro.pop();
    if(left == right) father[left] = f;
    else{
        for(int i = left; i <= right; i++){
            if(t == ino[i]){
                Build(left, i-1, i);
                Build(i+1, right, i);
                father[i] = f;
                break;
            }
        }
    }
}

void closest_father(int u, int v){
    int u1 = findOrder(u);
    int v1 = findOrder(v);
    if(u1 == 0 && v1 == 0) {cout << "ERROR: "<<u<<" and "<<v<<" are not found." << endl; return;}
    else if(u1 == 0) {cout << "ERROR: "<<u<<" is not found." << endl; return;}
    else if(v1 == 0) {cout << "ERROR: "<<v<<" is not found." << endl; return;}
    //输入值为两个根节点,则最近公共祖先是自己(根节点)
    if(u == v && u == root) { cout << v <<" is an ancestor of " << u << "." << endl;  return;}
    //如果两个数值相同,直接返回其父结点
    if(u == v){ cout <<"LCA of "<< u <<" and "<< v <<" is " << ino[father[u1]] << "." << endl;  return;}
    stack<int> s1,s2;
    int t = u1;
    //将u、v和其所有祖先节点压入栈中
    while(t != 0){
        s1.push(t);
        t = father[t];
    }
    t = v1;
    while(t != 0){
        s2.push(t);
        t = father[t];
    }
    int a,b,f;
    int flag = 0;
    while(!s1.empty() && !s2.empty()){
        a = s1.top(); s1.pop();
        b = s2.top(); s2.pop();
        if(a == b) f = a; //flag为0则表示是u或v其中有一个为另一个祖先结点
        else { flag = 1; break; }
    }
    if(s1.empty() && !flag){
        cout << u <<" is an ancestor of " << v << "." << endl;
        return;
    }
    if(s2.empty() && !flag){
        cout << v <<" is an ancestor of " << u << "." << endl;
        return;
    }
    cout <<"LCA of "<< u <<" and "<< v <<" is " << ino[f] << "." << endl;
}

int main()
{
    cin >> M >> N;
    int tp;
    for(int i = 1; i <= N; i++){
        cin >> tp;
        pro.push(tp);
        ino.push_back(tp);
    }
    father[0]= 0;
    ino.push_back(0);
    sort(ino.begin(), ino.end()); //二叉检索树排序后即可得到中序遍历顺序
    root = pro.front();
    Build(1,N,0);
    int u,v;
    while(M--){
        cin >> u >> v;
        closest_father(u,v);
    }
    return 0;
}
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值