二分算法由于其复杂度为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的情况,这时候可返回正确解。
原文地址:http://blog.csdn.net/zcube/article/details/45534001