数据结构-树-已知二叉树按顺序结构进行存储,求编号分别为i,j结点的公共祖先

1.算法思想
i>j,则先求i的父结点i/2。若 i/2 = j,则说明结点i及结点j的公共父结点为i/2。若i/2 != j,则令i = i/2,并继续进行循环,直到出现i=j的情况。那么j>i的情况与之类似
2.实现代码
①递归实现

ElementType Comm_Ancestor(SqTree T,int i,int j){
	if(i==j){ //递归出口
		return T[i];
	}
	else if(i>j){
		i = i/2;
		Comm_Ancestor(T,i,j);
	}
	else{
		j = j/2;
		Comm_Ancestor(T,i,j);
	}
}

②非递归实现

ElementType Comm_Ancestor(SqTree T,int i,int j){
	while(i!=j){
		if(i>j)
			i = i/2;
		else
			j = j/2;
	}
	return T[i];
}
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 可以先将i和j的路径分别出来,然后比较路径上最后一个相同的节点即可。具体步骤如下: 1. 根据i的编号出它在顺序存储结构中的下标index_i,假设根节点的下标为。 2. 根据下标index_i,可以出i的父节点的下标(index_i-1)/2。 3. 重复步骤2,直到找到根节点为止,将路径上的节点存储在一个数组path_i中。 4. 同样地,根据j的编号出它在顺序存储结构中的下标index_j,出j的路径path_j。 5. 从path_i和path_j的末尾开始比较,找到最后一个相同的节点即为它们的最近公共祖先节点。 6. 返回最近公共祖先节点的值即可。 时间复杂度为O(logn),其中n为二叉树的节点数。 ### 回答2: 首先需要明确一下顺序存储结构是指二叉树的节点按层次顺序依次存放在数组中,根节点存储在下标为1的位置,其左子节点存储在下标为2的位置,右子节点存储在下标为3的位置,依次类推。如果节点不存在,数组存储一个特定的值(如0)表示空节点。 接下来介绍一种解最近公共祖先节点的算法,时间复杂度为O(logn)。假设节点i和节点j都存在于二叉树中,且节点i在节点j的上方(即节点i在节点j的祖先节点中),那么节点i和节点j的最近公共祖先节点一定是节点i或节点i的某个祖先节点。反过来,如果节点j在节点i的上方(即节点j在节点i的祖先节点中),那么节点i和节点j的最近公共祖先节点一定是节点j或节点j的某个祖先节点。因此,我们可以先查找节点i和节点j的深度,然后让深度较深的节点先向上移动,直到两个节点所在的层次相同。接着同时向上移动两个节点,最终相遇的节点就是它们的最近公共祖先节点。 具体实现过程如下: 1. 分别计算节点i和节点j的深度d_i、d_j。 2. 如果d_i>d_j,则节点i向上移动d_i-d_j步,使得节点i和节点j处于同一层次。 3. 如果d_i<d_j,则节点j向上移动d_j-d_i步,使得节点i和节点j处于同一层次。 4. 同时向上移动节点i和节点j,直到它们相遇为止,相遇的节点即为它们的最近公共祖先节点。 时间复杂度分析:计算深度的过程需要遍历二叉树,时间复杂度为O(n);向上移动节点的过程最多移动logn次,每次移动的时间复杂度为O(1),因此时间复杂度为O(logn)。总时间复杂度为O(n+logn),即O(n)。 ### 回答3: 算法思路: 根据二叉树顺序存储的方式,我们可以通过节点的编号计算出节点在数组中的下标。假设节点 i 的下标为 x,节点 j 的下标为 y。 由于二叉树是任意的,因此我们不能通过顺序遍历的方式来寻找最近公共祖先节点。但是,我们可以通过寻找路径的方式来找到最近公共祖先。具体来说,我们可以先分别找到节点 i 和节点 j 的路径,然后寻找路径中最后一个相同的节点即为最近公共祖先。 我们可以通过递归的方式来寻找节点的路径。具体来说,如果当前节点为空,则路径不存在。如果当前节点已经是目标节点之一,则路径为当前节点。否则,我们递归地在左子和右子中查找目标节点,如果找到了目标节点,则将当前节点加入路径中。 算法实现: 1. 计算节点 i 和节点 j 在数组中的下标 x 和 y。 2. 分别寻找节点 i 和节点 j 的路径。为了方便计算,我们可以将节点路径用数组来表示。假设节点 i 的路径为 path_i,节点 j 的路径为 path_j,那么: ``` void findPath(int i, int x, int path[]) { if (x >= MAX_SIZE) { // 超出数组边界,节点不存在 path[0] = -1; return; } if (x == i) { // 找到了目标节点 path[0] = 1; path[1] = x; return; } findPath(i, x * 2, path); // 在左子中查找目标节点 if (path[0] == 1) { // 找到了目标节点 path[++path[0]] = x; return; } findPath(i, x * 2 + 1, path); // 在右子中查找目标节点 if (path[0] == 1) { // 找到了目标节点 path[++path[0]] = x; return; } path[0] = -1; // 没有找到目标节点 } int path_i[MAX_SIZE], path_j[MAX_SIZE]; findPath(i, 1, path_i); findPath(j, 1, path_j); ``` 3. 寻找路径中最后一个相同的节点。具体来说,我们从末尾开始遍历两个路径,直到遇到第一个不相同的节点为止。 ``` int k = 1; while (k <= path_i[0] && k <= path_j[0] && path_i[path_i[0] - k + 1] == path_j[path_j[0] - k + 1]) { k++; } k--; int lca = path_i[path_i[0] - k + 1]; ``` 完整代码如下:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xulidanga

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值