十九、二叉树的最近的公共祖先

十九、二叉树的最近的公共祖先

题目描述

设顺序存储的二叉树中有编号为 i 和 j 的两个结点,请设计算法求出它们最近的公共祖先结点的编号和值。

输入:

​ 输入第1行给出正整数n(≤1000),即顺序存储的最大容量;
第2行给出n个非负整数,其间以空格分隔。其中0代表二叉树中的空结点(如果第1个结点为0,则代表一棵空树);
第3行给出一对结点编号 i 和 j 。
题目保证输入正确对应一棵二叉树,且1≤ i,j ≤n。

输出:

如果i或j对应的是空结点,则输出:ERROR: T[x] is NULL,其中 x 是 i 或 j 中先发现错误的那个编号;否则在一行中输出编号为 i 和 j 的两个结点最近的公共祖先结点的编号和值,其间以一个空格分隔。

测试输入期待的输出时间限制内存限制额外进程
测试用例 115
4 3 5 1 10 0 7 0 2 0 9 0 0 6 8
11 4
2 31秒64M0
测试用例 215
4 3 5 1 0 0 7 0 2 0 0 0 0 6 8
12 8
ERROR: T[12] is NULL1秒64M0
测试用例 315
4 3 5 1 0 0 7 0 2 0 0 0 0 6 8
8 12
ERROR: T[8] is NULL1秒64M0

解题思路

求解结点的最近公共祖先(Least Common Ancestors,LCA),做法如下:

从根节点开始遍历

  • 如果node1和node2中的任一个和root匹配,那么root就是最低公共祖先。
  • 如果都不匹配,则分别递归左、右子树,
  • 如果有一个节点出现在左子树,并且另一个节点出现在右子树,则root就是最低公共祖先.
  • 如果两个节点都出现在左子树,则说明最低公共祖先在左子树中,否则在右子树。

注意,如果 i、j 是空节点,直接输出 ERROR。

上机代码:

在二叉树的存储结构中,data是输入序列中二叉树结点的值,vis是按照完全二叉树的顺序对应二叉树的结点的编号。通过 vis 可以更简单地判断二叉树向下查找时有没有超出边界,同时通过打印 vis 可以知道二叉树有没有正确地建立。

下面代码中的两个函数 in_sequence()print(),通过中序遍历打印 data 和 vis 的值,我借此来判断二叉树有没有正确建立,与本题关系不大。

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef struct NODE
{
	int data;	//结点的值
	int vis;	//结点的序号
	struct NODE *lchild;
	struct NODE *rchild;
}node, *Tree;

queue<Tree>q;
int n = 0, a[1010];//数组存储结点信息

void createTree()
{
	int flag = 0;
	Tree T, N;
	T = (Tree)malloc(sizeof(node));
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];

	//建立二叉树
	while (!q.empty())
	{
		flag++;
		T = q.front();
		q.pop();
		
		T->data = a[flag];
		T->vis = flag;

		N = (Tree)malloc(sizeof(node));
		N->data = -1;
		N->vis = -1;//没有访问过
		T->lchild = N;
		q.push(N);

		N = (Tree)malloc(sizeof(node));
		N->data = -1;
		N->vis = -1;
		T->rchild = N;
		q.push(N);

		if (flag == n)
			break;
	}
}
void in_sequence(Tree T)
{
	if (T->data != -1)
	{
		in_sequence(T->lchild);
		cout << T->data << " ";
		in_sequence(T->rchild);
	}
	return;
}
void print(Tree T)
{
	if (T->data != -1)
	{
		print(T->lchild);
		cout << T->vis << " ";
		print(T->rchild);
	}
	return;
}
Tree LCA(Tree T,int u,int v)
{
	if (T->vis == -1)//超出搜索范围
		return T;
	if (T->vis == u || T->vis == v)//找到u,v的值
		return T;
	Tree cur = (Tree)malloc(sizeof(node));
    
    //递归左右子树
	Tree left_lca = (Tree)malloc(sizeof(node));
	left_lca = LCA(T->lchild, u, v);
	if (left_lca->vis != -1)
	{
		cur = LCA(left_lca->lchild, u, v);
		if (cur->vis != -1)
			cur = LCA(left_lca->rchild, u, v);
		if ((cur->vis == u && left_lca->vis == v) || (cur->vis == v && left_lca->vis == u))
			return T;
	}
	
	Tree right_lca = (Tree)malloc(sizeof(node));
	right_lca = LCA(T->rchild, u, v);
	if (right_lca->vis != -1)
	{
		cur = LCA(right_lca->lchild, u, v);
		if (cur->vis != -1)
			cur = LCA(right_lca->rchild, u, v);
		if ((cur->vis == u && right_lca->vis == v) || (cur->vis == v && right_lca->vis == u))
			return T;
	}
	if (left_lca->vis != -1 && right_lca->vis != -1)
		return T;
	if (left_lca->vis == -1)
		return right_lca;
	else
		return left_lca;
}
int main()
{
	memset(a, -1, sizeof(a));
	Tree bit;
	bit = (Tree)malloc(sizeof(node));
	q.push(bit);
	createTree();

	/*
	in_sequence(bit);
	printf("\n");

	print(bit);
	printf("\n");
	*/

	int u = 0, v = 0;
	cin >> u >> v;
	if (a[u]==0)
	{
		printf("ERROR: T[%d] is NULL\n", u);
		//system("pause");
		return 0;
	}
	else if (a[v]==0)
	{
		printf("ERROR: T[%d] is NULL\n", v);
		//system("pause");
		return 0;
	}
	else
	{
		Tree tmp = (Tree)malloc(sizeof(node));
		tmp=LCA(bit, u, v);
		printf("%d %d\n", tmp->vis, tmp->data);
	}
	//system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值