前言
众所周知, 二分查找(Binary Search)是极其高效的查找方法, 在最坏的情况下才会以logN的时间运行, 时间复杂度表示为O(logN)
. 当然, 二分查找适用于已排序的数组. 二分查找开始于将数组中间的元素与目标值进行比较. 如果目标值与元素匹配, 则返回其在数组中的位置. 如果目标值小于该元素, 则搜索在数组的下半部分继续. 如果目标值大于元素, 则搜索将在数组的上半部分继续. 通过这样做, 该算法消除了每次迭代中不能匹配的一半.
算法1
int BinarySearch(int A[], int n, int elem){
int L = 0, R = n - 1, m = 0;
while(L <= R){
m = (L + R) / 2;
if(A[m] > elem){
R = m - 1;
}else if(A[m] < elem){
L = m + 1;
}else
return m;
}
return -1;
}
这个方法逻辑很简单, 但是有一个致命的问题就是如果遇到多次重复的项输出结果很不稳定.
总结一下算法1问题的原因: 每次执行时都会判断中值是否等于目标值, 若相等即输出.
算法21
int BinarySearch(int A[], int n, int elem){
int L = 0, R = n - 1;
float m = 0;
while(L != R){
m = ceilf((L + R) / 2.0);
if(A[(int)m] > elem){
R = m - 1;
}else
L = m;
}
if(A[L] == elem){
return L;
}
return -1;
}
我们改了一下判定方法, 这次的确稳定了, 稳定输出最后一项(虽说这样做的确没错, 包括算法1, 其实也是正确解), 但其实也不是很符合我们的逻辑, 我们可以在改进一下.
算法3
int BinarySearch(int A[], int n, int elem){
int L = 0, R = n - 1, m = 0;
while(L < R){
m = (L + R) / 2;
if(A[m] < elem){
L = m + 1;
}else
R = m;
}
if(A[R] == elem){
return R;
}
return -1;
}
这下改好了, 其实它也有一个输出最右端数的变形, 就交给爱思考的同学了
Hermann Bottenbruch published the first implementation to leave out this check in 1962. ↩︎