二叉查找树的向上取整/向下取整查找

本文介绍了一种在二叉查找树中实现向上和向下取整的算法,该算法可以找到大于等于或小于等于给定值的最近节点。通过递归方式实现,时间复杂度为O(logN)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此算法于《算法》P257有描述

 

所谓向上取整就是指大于等于x的最小整数,向下取整是指小于等于x的最大整数

此算法在二叉查找树中查找大于等于x的最小整数/小于等于x的最大整数

 

算法主要分为几种情况讨论(以向上取整为例):

1.当前节点的键值小于x:目标肯定位于当前节点的左子树,因为右子树>当前节点>目标节点,所以不可能在右子树

2.当前节点的键值大于x:目标肯定位于当前节点的右子树或目标为当前节点,因为当前节点为此时已知的小于等于x的最大整数,若在右子树中查找失败,则目标就是当前节点

3.当前节点的键值等于x:目标为当前节点,返回

4.当前节点为NULL:查找失败,返回NULL

 

将以上思路用递归实现就OK了~

代码如下:

 

TreePosition FindFloor(ElementType X, Tree T)
{
	TreePosition P;
	if (T == NULL)
		return NULL;
	else if (X < T->Element)
		//如果小于当前节点,则小于等于X的节点都在左子树内
		return FindFloor(X, T->Left);
	else if (X == T->Element)
		//如果等于当前节点,满足条件
		return T;
	else
	{
		//如果大于当前节点,则小于等于X的节点在右子树内,若右子树内查找失败
		//则当前节点为小于等于X的最大节点
		P = FindFloor(X, T->Right);
		if (P == NULL)
			return T;
		else
			return P;
	}
}

 

 

向下取整查找如法炮制,只需将Left与Right、<与>换下就OK~

代码如下:

 

TreePosition FindCeiling(ElementType X, Tree T)
{
	TreePosition P;
	if (T == NULL)
		return NULL;
	else if (X > T->Element)
		//若大于当前节点,则大于等于X的最小节点一定在右子树内
		return FindCelling(X, T->Right);
	else if (X == T->Element)
		return T;
	else
	{
		//如果小于当前节点,则一定在左子树内,若查找失败,
		//则当前节点为大于等于x的最小节点
		P = FindCelling(X, T->Left);
		if (P == NULL)
			return T;
		else
			return P;
	}

}

 

 

因为所有操作都沿着一条路径进行,而没有一条路径长于树的高度,所以时间复杂度为

O(logN)

 

<think>嗯,用户让我画一个长度为12的折半查找判定树。首先,我需要确认折半查找判定树是什么。折半查找也就是二分查找,判定树是用来表示查找过程的二叉树,每个节点代表一个中间元素,左右子树代表下一步的查找区间。 那长度为12的话,应该是查找表有12个元素。首先,我得回忆一下判定树的构建方法。每次选择中间元素作为根,然后左右子表递归处理。这里的关键是确定每个子树的根节点位置。 不过,当元素个数为偶数时,中间元素的选择有两种可能,通常取上中位数或者下中位数。比如12个数,第一次中间位置应该是第6个元素还是第7个?这里可能需要根据教材中的习惯来确定。一般来说,可能取$\lfloor (low+high)/2 \rfloor$或者$\lceil (low+high)/2 \rceil$。比如,当low=1,high=12时,中间位置可能是6或者7。不同的选择会影响树的结构。 假设第一次中间选第6个元素作为根节点。那左子树有5个元素(1-5),右子树有6个元素(7-12)。接下来,左子树的中间是3,右子树的中间如果是9的话,继续拆分。但这样可能导致左右子树的高度差异,进而影响树的高度是否平衡。 或者,如果第一次选第6个元素,左子树5个节点,右子树6个节点。递归下去,每个子树继续选择中间点。这时候需要构建每个节点的左右子树,直到所有子区间都被处理完毕。 接下来,我需要考虑判定树的深度,也就是查找长度。对于n=12的情况,判定树的深度应该是$\lfloor \log_2 12 \rfloor +1$,也就是4层,因为2^3=8,2^4=16,所以深度为4。 在构建树的结构时,需要确保每个节点的左右子树正确对应。比如根节点是6,左子树处理1-5,右子树处理7-12。然后左子树的中间是3,右子树的中间可能是9(假设取中间位置),接着继续分割下去。 可能遇到的问题是如何处理子区间长度为奇数偶数的情况。例如,左子树1-5有5个元素,中间是3;右子树7-12有6个元素,中间可能是9或者10。如果取第3个元素的位置的话,当子区间是7-12时,长度是6,中间位置应该是第3个元素的位置,即(7+12)/2=9.5,取9还是10?这里可能需要明确是向下取整还是向上取整。 根据通常的折半查找实现,中间位置计算是mid = low + (high - low) / 2,这样当low=7,high=12时,mid=7 + (12-7)/2=7+2=9(整数除法)。所以中间元素是第9个元素,即原数组中的第9个位置。 这样,右子树以9为根,左子树是7-8,右子树是10-12。然后继续递归构建。 接下来,每个子树继续拆分。例如,左子树1-5的根是3,其左子树是1-2,根是2;右子树是4-5,根是5。而右子树7-12的根是9,左子树7-8根是8,右子树10-12根是11,再继续拆分下去。 需要确保每个子树的根正确,并且最终形成的树的结构符合折半查找的过程。可能还需要考虑树的平衡性,因为折半查找的判定树应该是平衡的二叉排序树,深度差不超过1。 然后,具体画出树的结构可能需要用层次化的方式表示,比如根节点在顶部,左右子树依次向下展开。每个节点的数值代表比较的关键字位置。 最后,验证树的正确性,确保每个节点的左右子树符合折半查找的分区,并且所有12个元素都被正确包含在树中,没有遗漏或重复。</think>下面逐步介绍如何构建长度为12的折半查找判定树: --- ### 一、判定树基本概念 折半查找判定树是描述二分查找过程的二叉树: - 每个节点表示一次关键字比较 - 左子树对应查找区间左半部分 - 右子树对应查找区间右半部分 --- ### 二、构建步骤分析(n=12) 1. **确定根节点** 初始查找区间[1,12],中间位置计算: $$ mid = \lfloor (1+12)/2 \rfloor = 6 $$ **根节点为6** 2. **构建左子树(区间[1,5])** - 新中间位置:$\lfloor (1+5)/2 \rfloor = 3$ - **左子树根为3** - 递归处理子区间[1,2][4,5] 3. **构建右子树(区间[7,12])** - 新中间位置:$\lfloor (7+12)/2 \rfloor = 9$ - **右子树根为9** - 递归处理子区间[7,8][10,12] 4. **递归完成所有子区间** 继续对每个子区间重复上述过程,直到所有元素被覆盖 --- ### 三、完整判定树结构 ```plaintext 6 / \ 3 9 / \ / \ 1 5 7 11 \ / \ / \ 2 4 8 10 12 ``` #### 关键特性验证: 1. **节点总数**:12个(对应查找表中的元素) 2. **树高度**:4层(最大查找次数为4) 3. **平衡性**:满足平衡二叉树特性(左右子树高度差≤1) --- ### 四、查找过程示例 假设查找元素8: 1. 比较6 → 进入右子树 2. 比较9 → 进入左子树 3. 比较7 → 进入右子树 4. 比较8 → 查找成功(共4次比较) --- ### 五、注意事项 1. **中间位置计算**:始终采用向下取整 2. **平衡性保证**:折半查找树本质是平衡二叉搜索树 3. **失败节点**:实际应用中需补充失败节点(本示例未显示)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值