二分算法总结

二分算法由于其复杂度为O(logN),在实际运算中具有极高的效率。二分算法思想还经常结合其它算法被应用在解决实际项目问题中。例如,对非线性方程求根。

二分算法的思想简单,但编写正确却并不容易。编写二分算法的错误,往往不是因为疏忽错误,而是因为该算法过于灵活却暗藏杀机。轻则程序崩溃,机器停止;重则可能引起致命的损失。

下面先给出错误程序,及样例分析。

错误1:

int bsearch(int *a, int x, int y, int v) {
    int m
    while (x < y) {
        int m = x + (y - x) / 2;
        if (v == a[m])
            return m;
        else if (a[m] > v)
            y = m;
        else
            x = m;
    }
    return -1;
}

假设x = 2,y = 3,a[3] == v。这时候程序将进入死循环,因为m经过运算始终等于2;a[2] < v始终进行x = m;所以x始终小于y。

错误2:

int bsearch(int *a, int x, int y, int v) {
    int m
    while (x < y) {
        int m = x + (y - x) / 2;
        if (v == a[m])
            return m;
        else if (a[m] > v)
            y = m-1;
        else
            x = m+1;
    }
    return -1;
}

假设x = 0,y = 4,a[1] == v。这时候程序将返回-1,而不是1。经过运算m == 2,又因为a[2] > v,所以执行y = m-1。这时候y = 1,循环重新开始,运算后m == 0,经过下面判断语句得到x == 1,这时候循环跳出,忽略了m == 1情况,最后结果错误。
针对错误1的正确程序应该为:


int bsearch(int *a, int x, int y, int v) {  int m
    while (x < y) {
        int m = x + (y - x) / 2;
        if (v == a[m])
            return m;
        else if (a[m] > v)
            y = m;
        else
            x = m + 1;
    }
    return -1; 
}

这里之所以将x = m+1,而不是y = m-1,是因为相邻整数x,y经过m = x + (y + x)/2运算后都是得到的m值总是趋于最小值。例如,x = 2,y = 3,最后得到m == 2。
针对错误2的正确程序应该为:

int bsearch(int *a, int x, int y, int v) {
    int m
    while (x <= y) {
        int m = x + (y - x) / 2;
        if (v == a[m])
            return m;
        else if (a[m] > v)
            y = m - 1;
        else
            x = m + 1;
    }
    return -1;
}

鉴于上面错误2情况,将x < y修改为x <= y后,当x == 1、y == 1时候循环并不会结束,而是继续进行运算得到m == 1的情况,这时候可返回正确解。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。