knuth 在TAOCP有过这么一句话: 虽然第一篇二分搜索在1946年就发表了, 但是第一个没有错误的二分搜索程序直到1962年才出现。 所以可以说是是最简单的难题了。
问题: 给定排好序的N个distinct elements 的array, 使用最少的比较次数确定某一个值是否存在。
分析: 线性查找的时间复杂度是O(n), 但是考虑到数组是sorted, 所以我们一定要利用好这个信息。 使用二分搜索更好, 理论上, 最坏情况下, 比较次数需要log(N) + 1。
#include <iostream>
using namespace std;
int Binary_Search(int A[], int l, int r, int x) {
int m = 0;
while(l <= r) {
m = l + (r - l)/2;
if(A[m] == x)
return m;
if(A[m] < x)
l = m + 1;
else
r = m - 1;
}
return -1;
}
int main() {
int A[6] = {1, 2, 3, 4, 7, 8};
int p = 0;
p = Binary_Search(A, 0, 5, 8);
cout << p << endl;
p = Binary_Search(A, 0, 5, 2);
cout << p << endl;
p = Binary_Search(A, 0, 5, 6);
cout << p << endl;
}
运行结果:
不难看出, 上面的程序, while语句在每一次迭代的时候, 如果第一个比较不成立, 即没找到, 那么就会还会再次执行一次比较。 如此, 一次不成功的迭代比较了两次, 能不能做改进, 从而减少比较的次数。 答案是可以的。 改进如下:
Binary_Search2(int A[], int l, int r, int x) {
int m = 0;
while(r - l > 1) { // 退出的时候, 表明r - l == 1
m = l + (r - l)/2;
// 即A[l] <= x
if(A[m] <= x) {
l = m;
}
// 即A[r] > x
else {
r = m;
}
// 退出循环后, 表明r - l == 1, 只需要判断A[l]和X 是否相等即可
if(A[l] == x) {
return l;
}
else {
return -1;
}
}
}
问题二:给定一个具有N个distinct integers的array, 找出给定的x的floor。 例如A = {-1, 2, 3, 5, 6, 8, 9, 10},给定x = 7, 应该返回的值是6。
程序如下:
int Floor(int A[], int l, int r, int x) {
int m = 0;
while(r - l > 1) {
m = l + (r - l)/2;
if(A[m] <= x)
l = m;
else
r = m;
}
return A[l];
}
// 调用, 包含错误检测
int Floor(int A[], int n, int x) {
if(x < A[0])
return -1;
return Floor(A, 0, n, x);
}
问题: 给定一个sorted array of distinct elememts, 这个sorted array rotated to an unknow position, 现在我们的任务就是找到这个rotated sorted array的最小值(找到最小值的位置, 我们当然就知道其rotated的情况)。
程序:
int RotatedSortedArrayMin(int A[], int l, int r) {
int m = 0;
// 前提条件: A[l] > A[r]
if( A[l] <= A[r] )
return l;
while( l <= r ) // 退出循环条件时l > r
{
// 终止条件, l最终落在r上,r指向的是最小值的位置索引
if( l == r )
return l;
m = l + (r-l)/2; // 'm' can fall in first pulse,
// second pulse or exactly in the middle
if( A[m] < A[r] )
// 此时最小值不可能在区间
// (m < i <= r)上, we can exclude A[m+1 ... r]
r = m;
else // A[m] >= r
// min must be in the range (m < i <= r),
// we must search in A[m+1 ... r]
l = m+1;
}
return -1;
}
int RotatedSortedArrayMin(int A[], int n)
{
return RotatedSortedArrayMin(A, 0, n-1);
}
问题: Searhing an element in a rotated sorted array:
int rotated_binary_search(int A[], int N, int key) {
int L = 0;
int R = N - 1;
while (L <= R) {
// 使用下面的式子而不是 M=(L+R)/2的好处的避免溢出
int M = L + ((R - L) / 2);
// 返回条件
if (A[M] == key) return M;
// 下半部分A[L..M]是排好序的
if (A[L] <= A[M]) {
// 确定key所在的区间: A[L] <= key <= A[M]
if (A[L] <= key && key < A[M])
R = M - 1;
else
L = M + 1;
}
// 上半部分(条件A[L] > A[M]) A[M...R]是排好序的
else {
if (A[M] < key && key <= A[R])
L = M + 1;
else
R = M - 1;
}
}
return -1;
}