二分查找
原理
对于一个已经排序的数组,我们可以使用二分查找,在O(logN)的时间内找到特定的元素
具体的步骤如图:

比如,如果我们想找到6这个数
- 我们可以先找到8,发现8比6大
- 往左边走,在左半部分,找到中间位置,是3,发现3比6小
- 往右边走,在8和3之间,找到了6
如果查找56,则第二步向右移动
我们每次都和候选空间的中间位置做比较,每次的步长都是一半的区域,所以时间复杂度是 O(logN)
代码
非递归
int bsearch(int* arr, int target, int left, int right) {
if (arr == nullptr) {
return -1;
}
while (left <= right) {//这里的运算符是 <=
int mid = left + (right - left) / 2; // 这里不用 (left+right)/2,可以防止整数溢出
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
递归
int bsearch(int* arr, int target, int left, int right) {
if (arr == nullptr || left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
return bsearch(arr, target, left, mid - 1);
} else {
return bsearch(arr, target, mid + 1, right);
}
return -1;
}
变形
旋转后的排序数组
如果一个数组定义为这样:
int arr[] = {33, 56, 78, 98, 1, 2, 3, 6, 7, 8, 9, 22};
这个排序数组,做了一个旋转,乍一看,不能使用二分查找,其实,不能被这个调整给吓到了,这里也是有规律的,只是稍微麻烦点而已。不要怕麻烦。
对于 {33, 56, 78, 98, 1, 2, 3, 6, 7, 8, 9, 22},中间位置的数小于最右边的数,说明右半部分是有序的,如果要找的数正落在右半部分,则可以使用二分查找了,如果没有落在右半部分,可以递归。
同理,对于{8, 9, 22, 33, 56, 78, 98, 1, 2, 3, 6, 7},中间位置的数大于最左边的数,说明左半部分是有序的,可以分情况二分查找,或者递归。
所以,这里的代码为:
#include <iostream>
int bsearch(int* arr, int target, int left, int right) {
if (arr == nullptr || left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
return bsearch(arr, target, left, mid - 1);
} else {
return bsearch(arr, target, mid + 1, right);
}
return -1;
}
int func(int* arr, int target, int left, int right) {
if (arr == nullptr || left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > arr[left]) {
if (arr[mid] > target && target >= arr[left]) {
return bsearch(arr, target, left, mid - 1);
} else {
return func(arr, target, mid + 1, right);
}
} else {
if (arr[mid] < target && target <= arr[right]) {
return bsearch(arr, target, mid + 1, right);
} else {
return func(arr, target, left, mid - 1);
}
}
return -1;
}
void test1() {
int arr[] = {8, 9, 22, 33, 56, 78, 98, 1, 2, 3, 6, 7};
int len = sizeof(arr) / sizeof(int);
printf("%d, %d, %d, %d", func(arr, 8, 0, len - 1) == 0,
func(arr, 7, 0, len - 1) == len - 1, func(arr, 98, 0, len - 1) == 6,
func(arr, 22, 0, len - 1) == 2);
}
int main() {
test1();
return 0;
}
浙公网安备 33010602011771号