顺序存储的二叉树的最近的公共祖先问题
题目概述
给定一棵顺序存储的二叉树和编号为i和j的两个节点,求它们的最近公共祖先。
输入格式
第1行给出正整数n(≤1000),即顺序存储的最大容量;第2行给出n个非负整数,其间以空格分隔。其中0代表二叉树中的空结点(如果第1个结点为0,则代表一棵空树);第3行给出一对结点编号i和j。
输出格式
如果i或j对应的是空结点,则输出ERROR: T[x] is NULL,其中x是i或j中先发现错误的那个编号;否则在一行中输出编号为i和j的两个结点最近的公共祖先结点的编号和值,其间以1个空格分隔。
输入样例
15
4 3 5 1 10 0 7 0 2 0 9 0 0 6 8
11 4
输出样例
2 3
解题思路
考虑到顺序二叉树的特殊性质,我们可以通过二叉树节点编号的大小关系来简化问题。对于节点i,其左子节点为2i,右子节点为2i+1,而其父节点为i/2。因此,我们可以通过循环判断它们的大小关系来找到最近公共祖先。
具体思路为:
-
首先,我们输入顺序二叉树和节点编号i、j。
-
判断i和j是否代表错误节点,如果其中一个是错误节点,则输出相应信息。
-
如果i和j相等,则i即为节点的最近公共祖先,输出节点编号i和它的值即可。
-
如果以上判断不成立,我们可以通过循环判断i和j节点的大小关系来找到它们的最近公共祖先。具体地,假设i>j,我们将i变为它的父节点i/2。如果i<=j,则将j变为它的父节点j/2。如果i==j,则i即为它们的最近公共祖先。
参考代码
下面给出一种基于循环的实现方式。
首先,我们定义了一个整型数组 binTree,用于存储顺序二叉树的节点值。根据题意,输入顺序二叉树节点数 n 和节点值,并存储在数组 binTree 中。
然后,我们输入第二行两个节点编号 num1 和 num2。根据题意,我们需要输出节点 num1 和 num2 的最近公共祖先。我们调用了 findFather 函数来计算最近公共祖先节点编号 result,并将其存储在 result 变量中。
接着,我们使用条件判断语句对 result 进行判断,判断节点 num1 和 num2 是否是错误节点,或者它们是否代表同一个节点。如果以上判断不成立,则输出节点 num1 和 num2 的最近公共祖先节点编号和值。
int findFather(int a,int b)
{
while(1)
{
if(a>b)
a=a/2;
else if(a<b)
b=b/2;
if(a==b)
break;
}
return a;
}
findFather 函数的主体思路为,通过 while 循环依次判断节点编号的大小关系,从而找到它们的最近公共祖先节点编号。具体地:
- 如果 a > b,则将 a 变为 a/2,即将 a 变为其父节点。
- 如果 a < b,则将 b 变为 b/2,即将 b 变为其父节点。
- 如果 a = b,则 a 即为节点的最近公共祖先节点。
因为树的高度为 \(\log n\) 级别,所以在最坏情况下,该算法的时间复杂度为 \(O(\log n)\)。
最后,根据题目要求输出答案即可。如果其中一个节点是错误节点,则输出相应的错误信息。
#include <stdio.h>
// 计算两个节点的最近公共祖先
int findFather(int a, int b);
int main() {
int binTree[1001] = {0}; // 顺序存储二叉树,初始化所有节点值为 0
// 输入顺序二叉树节点数 N 和节点值,存储在数组 binTree 中
int N, i;
scanf("%d", &N);
for (i = 0; i < N; i++) {
scanf("%d", &binTree[i]);
}
// 输入需要查询的两个节点编号 num1 和 num2
int num1, num2, result = 0; // i 用在循环了,不用 i
scanf("%d %d", &num1, &num2);
// 计算 num1 和 num2 的最近公共祖先,存储在 result 中
result = findFather(num1, num2);
// 根据题目要求输出结果
if (num1 == num2) { // 如果两个节点编号相同,则它们即为最近公共祖先,直接输出节点编号和节点值
printf("%d %d\n", num1, binTree[num1 - 1]);
} else if (binTree[num1 - 1] == 0) { // 如果 num1 代表一个空节点,则输出错误信息
printf("ERROR: T[%d] is NULL\n", num1);
} else if (binTree[num2 - 1] == 0) { // 如果 num2 代表一个空节点,则输出错误信息
printf("ERROR: T[%d] is NULL\n", num2);
} else { // 输出最近公共祖先的节点编号和节点值
printf("%d %d\n", result, binTree[result - 1]);
}
return 0;
}
// 计算 num1 和 num2 的最近公共祖先
int findFather(int num1, int num2) {
int ancestor = 0; // 最近公共祖先节点编号
// 循环判断 num1 和 num2 的父节点是否相同,直到找到它们的最近公共祖先节点编号
while (1) {
if (num1 > num2) { // 如果 num1 的编号大于 num2,则将 num1 变为它的父节点
num1 = num1 / 2;
} else if (num1 < num2) { // 如果 num1 的编号小于 num2,则将 num2 变为它的父节点
num2 = num2 / 2;
} else { // 如果 num1 和 num2 的编号相同,则它们的最近公共祖先即为它们的父节点
ancestor = num1;
break;
}
}
return ancestor;
}

浙公网安备 33010602011771号