正确的二分查找算法

来源:互联网 发布:泰牛程序员没工作 编辑:程序博客网 时间:2024/06/10 15:06

虽然很早就接触二分查找算法,但是要写个正确的二分查找还是很费功夫的。



//二分查找。 在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;}