二分查找的典型Bug

看到一篇文章《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/p/2357876.html