折半查找(Binary Search)是一种减治思想的算法,即每次将问题的规模减半,以达到快速查找到目标元素的目的。因为对于一个有序数组而言(假设是非降序排列的),若数组中间的元素大于目标元素,则其后面的所有元素都是大于目标元素的,因此我们只需要在其前面的元素中查找即可;反之,若数组中间的元素小于目标元素,则其前面的元素都是小于目标元素的,因此我们只需要在其后面的元素中查找即可。
当然,折半查找的前提是,所要查找的数组必须是有序的!!!否则不能使用折半查找。
具体减治法的思想可以参考我的另一篇博文:《减治法》
先上伪代码
因为伪代码没有其他语言的语法限制,能够有助于我们更好地将注意力放在算法上,所以这里我们先用伪代码来讲述一下主要思想:
algorithm binarySearch(A[0..n-1], data)
//使用折半查找算法在升序数组A中找到元素data,有则返回元素的位置,否则返回-1
//输入:一个升序数组A以及待查找元素data
//输出:目标元素的位置或者-1
low <- 0;high <- n-1
while low <= high do
middle = (low + high) / 2 //向上取最小或者向下取最大都可以,这里向下取最大
if data = A[middle] return middle
else if data < A[middle] high = middle - 1 //目标元素小于中间元素,则应该在左边
else low = middle + 1 //目标元素大于中间元素,则应该在右边
return -1 //找不到就返回-1
代码实现
折半查找算法:
int binarySearch(int* data, int n) {
int low = 0;
int high = 9;
while (low <= high) {
int middle = (low + high) / 2;
if (data[middle] == n) return middle + 1;
else if (data[middle] < n) low = middle + 1;
else high = middle - 1;
}
return -1;
}
然后在main函数中运行:
int main() {
int data[10] = { 1, 3, 4, 5, 7, 8, 12, 35, 44, 57 };
cout << "2在数组中的位置:" << binarySearch(data, 2) << endl;
cout << "12在数组中的位置:" << binarySearch(data, 12) << endl;
return 0;
}
运行结果如下:
时间复杂度分析
最优情况:即刚好出现在middle位置上,那么时间复杂度为O(1)
最差情况:即刚好要等到low=high时,才能够确定是否存在,则时间复杂度为O(logn)
那么是否查找算法已经无法再进一步优化了呢?
不!还有一种比它更好的算法——插值查找,它的复杂度为O(loglogn)。
请参考我的另一篇博文《插值查找——一个比折半查找更好的查找算法》
参考资料
《算法设计与分析基础》第三版以及老师的课件