二分查找的典型Bug

本文深入探讨了二分查找算法中常见的溢出问题,并提供了三种有效的修复策略,包括改进的中间值计算方法和适用于C/C++环境的替代方案。通过实例分析,确保了算法在实际应用中的稳定性和效率。

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

看到一篇文章《Extra, Extra - Read All About It: Nearly All Binary Searches and Mergesorts are Broken

说的是很多二分查找都有bug,包括《编程珠玑》上给出的实现。这个bug也曾经出现在java.util中。

典型的Java版实现是

int binarySearch(int a[], int key, int length) {
	int low = 0;
	int high = length - 1;
	while (low <= high) {
		int mid = (low + high) / 2;
		int midVal = a[mid];
		if (midVal < key) 
			low = mid + 1
		else if (midVal > key)
			high = mid - 1;
		else
		return mid;     // key found
 }
 return -(low + 1);  // key not found
}

在int mid = (low + high) / 2;这句中,两个数相加可能导致溢出。

文章给出来修复bug的方式

So what's the best way to fix the bug? Here's one way:
6: int mid = low + ((high - low) / 2);
Probably faster, and arguably as clear is:
6: int mid = (low + high) >>> 1;
In C and C++ (where you don't have the >>> operator), you can do this:
6: mid = ((unsigned int)low + (unsigned int)high)) >> 1;

当然第三种方式在C99下不能保证正确,

if you add two signed quantities and get an overflow, the result is undefined

当然,根据C++中迭代器的思想,low和high是迭代器(指针的抽象),所以,一般情况下用

mid = low + (high - low)>>1;

这样思想的比较多,也具有普遍的通用性,强烈推荐之。

 



转载于:https://www.cnblogs.com/westfly/archive/2012/02/19/2357876.html

<think>嗯,用户问的是如何进行查找操作,需要查找方法。首先得明确用户的具体需求是什么。查找操作有很多种场景,比如在数据结构里找元素,或者在文档里搜索关键词,或者是编程中的查找算法。可能需要覆盖不同的情况。 用户可能是一个程序员,想了解不同的查找算法,比如线性查找、二分查找之类的。或者可能是在处理文本数据时需要高效的搜索技巧。也有可能是数据库中的查询方法。得先确定范围,但用户的问题比较泛,可能需要涵盖多个方面。 接下来需要调用网络搜索工具,查找常见的查找方法,可能包括基本算法、应用场景、实现步骤。然后整合这些信息,确保回答清晰有操作性。根据任务要求,要分步骤或方法,每个部分换行,不用首先、然后这样的词。 还要注意引用不能堆在最后,所以每个方法里如果有引用内容,需要直接整合进去。比如提到二分查找时,要说明它适用于有序数组,时间复杂度是O(log n),然后给出代码示例。代码和公式的格式要正确,行内公式用$,独立用$$,代码用三个反引号加语言类型。 然后生成相关问题部分,必须三个,基于原始问题和回答内容。比如可能的问题有不同查找算法的时间复杂度比较,二分查找的具体实现细节,或者哈希表的冲突解决方法。这些问题需要和用户的问题相关,并且帮助用户深入理解。 需要确保回答结构正确,方法分点,每个方法间换行,避免第一人称,步骤词汇。检查是否有遗漏的格式要求,比如代码和公式是否正确,相关问题的标题是否正确,有没有多余的空格或换行。 最后测试是否符合所有要求,特别是格式部分,因为用户强调了严格遵循,否则会导致bug。可能还需要验证搜索结果的准确性,确保提供的方法正确且实用。</think>针对不同场景的查找操作可分为以下方法实现: **线性查找** 适用于无序数据集或小型数据集合,逐个元素比对直到找到目标值。时间复杂度为$O(n)$,实现简单但效率较低 ```python def linear_search(arr, target): for i in range(len(arr)): if arr[i] == target: return i return -1 ``` **二分查找** 要求数据集已排序,通过不断缩小查找范围提高效率。时间复杂度为$O(\log n)$,适用于静态数据集 ```python def binary_search(arr, target): left, right = 0, len(arr)-1 while left <= right: mid = (left + right) // 2 if arr[mid] == target: return mid elif arr[mid] < target: left = mid + 1 else: right = mid - 1 return -1 ``` **哈希表查找** 通过哈希函数建立键值映射关系,实现平均$O(1)$时间复杂度的查找。需要处理哈希冲突,常见解决方法包括开放寻址法和链地址法。Python字典是典型实现: ```python hash_table = {'apple': 5, 'banana': 7} print(hash_table.get('apple', 0)) # 输出5 ``` **树结构查找** 二叉搜索树(BST)通过节点值比较进行查找,平衡二叉树如AVL树、红黑树可保持$O(\log n)$时间复杂度。B树及其变种适用于磁盘存储的大规模数据 **字符串匹配** KMP算法通过预处理模式串构建部分匹配表,将时间复杂度优化到$O(n+m)$。计算公式中部分匹配表时需计算最长公共前后缀长度: $$PMT[i] = \max\{k | pattern[0:k] == pattern[i-k+1:i]\}$$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值