树中第一个公共祖先结点----解法

本文提供了优快云博客的一个示例链接,详细内容请访问该链接获取。
不能转载,只能放一个地址了http://blog.youkuaiyun.com/xyzbaihaiping/article/details/52122885
**题目重述** 给定一个顺序存储的二叉(数组形式,下标从1开始),以及两个结点编号 $ i $ 和 $ j $,求它们的**最近公共祖先**(LCA)的编号和值。若任一结点为空,则输出错误信息。 --- **详解** 顺序存储的二叉树中,父节点与子节点的下标关系为: - 对于编号为 $ k $ 的结点- 其父结点编号为:$ \left\lfloor \frac{k}{2} \right\rfloor $ - 左孩子编号为:$ 2k $ - 右孩子编号为:$ 2k+1 $ 利用这一性质,我们可以将问题转化为:从 $ i $ 和 $ j $ 出发,不断向上找父节点,直到找到第一个共同祖先。 ### 解法步骤: 1. **检查合法性**:若 `T[i-1] == 0` 或 `T[j-1] == 0`(注意数组下标从0开始),则对应结点为空。 2. **路径回溯法**: - 从 $ i $ 开始,将其所有祖先(包括自己)标记。 - 再从 $ j $ 向上回溯,第一个已被标记的祖先即为 LCA。 3. 输出结果。 ### C语言实现代码: ```c #include <stdio.h> int main() { int n; scanf("%d", &n); int tree[1000]; for (int i = 0; i < n; i++) { scanf("%d", &tree[i]); } int i, j; scanf("%d %d", &i, &j); // 检查是否为空节点 if (tree[i - 1] == 0) { printf("ERROR: T[%d] is NULL\n", i); return 0; } if (tree[j - 1] == 0) { printf("ERROR: T[%d] is NULL\n", j); return 0; } // 标记 i 到根路径上的所有节点编号 int visited[1001] = {0}; // 记录路径上节点编号 int temp = i; while (temp >= 1 && temp <= n) { visited[temp] = 1; if (temp == 1) break; temp /= 2; // 父节点编号 } // 回溯 j 到根,找第一个在 i 路径上的公共节点 temp = j; while (temp >= 1 && temp <= n) { if (visited[temp]) { printf("%d %d\n", temp, tree[temp - 1]); return 0; } temp /= 2; } return 0; } ``` --- ### 输入样例分析 #### 样例1: 输入: ``` 15 4 3 5 1 10 0 7 0 2 0 9 0 0 6 8 11 4 ``` 数组下标对应: | 编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 | |------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| | 值 | 4 | 3 | 5 | 1 |10 | 0 | 7 | 0 | 2 | 0 | 9 | 0 | 0 | 6 | 8 | - 结点11:值为9,路径:11 → 5 → 2 → 1 - 结点4:值为1,路径:4 → 2 → 1 - 公共祖先最早交汇于编号2(值为3) - 输出:`2 3` #### 样例2: ``` 15 4 3 5 1 0 0 7 0 2 0 9 0 0 6 8 12 8 ``` - tree[11] = 0 → T[12] is NULL → 输出错误 --- **知识点** 1. **顺序存储二叉父子关系**:编号 $ k $ 的父节点是 $ \left\lfloor \frac{k}{2} \right\rfloor $。 2. **路径回溯法求LCA**:通过向上遍历至根节点,寻找第一条共享路径。 3. **空节点判断**:若对应数组值为0,则表示空结点,需提前处理错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值