二分查找的典型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;
这样思想的比较多,也具有普遍的通用性,强烈推荐之。