虽然很早就接触二分查找算法,但是要写个正确的二分查找还是很费功夫的。
//二分查找。 在num数组中查找key, 若成功,返回下标。若失败,返回-1。参数len从0开始计。
第一版有问题的代码如下:
int bsearch1(int* num, uint8_t len, int key)
{
if (len == 0) {
return -1;
}
uint8_t start = 0;
uint8_t end = len - 1;
uint8_t mid = 0;
while (start <= end) {
//不用 mid = (start + end)/2 ,是因为start + end可能会溢出。因为你不能假定外界的数据有多大。就算start类型为uint64_t, 也不能保证。
// mid = start/2 + end/ 2;虽然也不能应对所有的情况,但是相比较而言,更可靠一些。
mid = start/2 + end/ 2;
if (key == num[mid]) {
return mid;
}
if (key < num[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return -1;
}
int key = 5;
int num[] = {1,2,4,5};
int ret = bsearch1(num, sizeof(num)/sizeof(int), key);
将会失败。因为
mid = start/2 + end/ 2;党start 和end都是3时,mid应该等于3,但此时
mid永远等于2, 所以是个无限循环。
下面是改进过的代码, 如果start 和end都是奇数,则mid 加1。
int bsearch(int* num, int len, int key)
{
if (len == 0) {
return -1;
}
uint8_t start = 0;
uint8_t end = len - 1;
uint8_t mid = 0;
while (start <= end) {
mid = start/2 + end/ 2;//avoid overflow
if ((start & 0x01) && (end & 0x01)) {
mid += 1;
}
if (key == num[mid]) {
return mid;
}
if (key < num[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return -1;
}