二分查找首先最最重要就是你要查询的目标数组是一个有序的数组
直接上代码
#include <stdio.h>
int binarysearch(int arr[], int size, int key) {
int left = 0;
int right = size - 1;
while (left <= right) {
int mid = (right + left) >> 1;
if (key == arr[mid]) {
return mid;
}
else if (key > arr[mid]) {
left = mid + 1;
}
else if (key < arr[mid]) {
right = mid - 1;
}
}
return -1;
}
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int size = sizeof(arr) / sizeof(arr[0]);
int key = 0;
printf("你要在1-9查找哪一个数字?\n");
scanf_s("%d", &key);
int num = binarysearch(arr, size, key);
if (num) {
printf("找到%d了!下标是%d", arr[num], num);
}
else {
printf("没找到个数字!");
}
return 0;
}
来说第一种方式
主要就是这一句right = size -1;这个 我们要知道所有的运算其实都是下标运算如果是size - 1那就刚好匹配到数组下标每个数都可以找到,换而言之就是形成了一个左闭右闭的这个区间【left,right】
假设我们要找这个key为2
进入循环第一次
之后我们的mid就是key了就直接返回了
为啥要每次循环是right = mid -1;呢 以为这个是闭区间也就是可以找到right然而mid在上一轮已经比过了所以没必要在进行一次所以说mid - 1
为啥在循环条件里面有等于号呢,举个特例如果key是1 or 9你没有等于号的话1和9是找不到的,其实他的根本原因是你right是size - 1的问题你就导致你的数组内是可以索引到的,那什么时候停止呢带等于号的话while(left <= right)当left == right + 1就停止了,带入数字看一下【8.7】不可能有个数字大于8小于7吧!
接下来来说第二种方式
#include <stdio.h>
int binarysearch(int arr[], int size, int key) {
int left = 0;
int right = size;
while (left < right) {
int mid = (right + left) >> 1;
if (key == arr[mid]) {
return mid;
}
else if (key > arr[mid]) {
left = mid;
}
else if (key < arr[mid]) {
right = mid;
}
}
return -1;
}
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int size = sizeof(arr) / sizeof(arr[0]);
int key = 0;
printf("你要在1-9查找哪一个数字?\n");
scanf_s("%d", &key);
int num = binarysearch(arr, size, key);
if (num) {
printf("找到%d了!下标是%d", arr[num], num);
}
else {
printf("没找到个数字!");
}
return 0;
}
这个主要是这一句right = mid 刚刚不是要减1吗这块咋又不减了?
是因为你right赋值是size 我们知道这个left 和 right mid 都是下标你数组原本最大的下标是size - 1你却给他个size 我直接 arr[right] 是越界的,换而言之也就是说这时候的范围是【left,right)左闭右开的,下一次循环的时候 mid 就被剔除出去了你的搜索区间就是【left,mid)和【mid + 1,rigth)你right = mid 其实也就是 mid下标的前一个元素来比较。
假设我们要找这个key为2
最后arr[mid] == key找到了
这次循环退出的条件咋不能等于了while(left < right)那就是left == right 带入数字就是【8,8)你分开这个再去按照【left,mid)和【mid + 1,rigth)是空的找不了了。
然后就是这个算法的改进
也就是这一句
(right + left) >> 1
改成
left + ((right - left) >> 1);
来防止溢出 我们画个图来理解一下
前者就可能造成溢出问题 后者可能性就小 要是left + right 很大超过 int 的21亿多一点点范围呢,这个left + right 的值还准确吗?
时间复杂度:
我们可以看出来O()