当我们想在一串数组中查找某个数对应的下标时,我们首先能想到的办法是从第一个开始,挨着往后去查找。(这里我们默认为递增数组,也可以先排序成递增数组)
但是这样的话需要花费的时间很多,于是我们就想有没有简单又没那么耗时的办法呢?
当然是有的,那就是我们的二分查找法。
二分查找法可以这样来理解:
小明告诉小红自己今天买了一双鞋,价格在1-100之间,让小红猜这双鞋的价格。
我们不会从1开始猜吧,我们一般都是从中间50开始猜。
小红说:“50。”
小明说:“猜小了”
然后范围就变成50-100了
小红又说:“75”
小明说:“猜大了”
于是范围又变成了50-75,就这样以此类推,直到最终猜到正确的价格。
那这个就和我们需要的查找下标是一样的道理,明白了之后我们就一起来写代码吧!
首先我们先写出数组,这里默认为升序
然后我们要查找中间值我们肯定需要知道这个数组的的长度来计算中间值,于是我们用到了sizeof来计算长度,用整个数组的长度来除数组第一个数的长度(4个字节),来求出整个数组的长度。
接下来是左右下标。注意这里的右下标为长度减一!
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]);//计算长度 strlen计算是不包含\0的 int left = 0; int right = sz - 1; printf("请输入一个数:"); scanf("%d", &i);
现在就是书写我们需要查找的值和中间值大小的比较了
在这里我们将中间坐标设为mid,中间值为arr[mid]
将它与我们要查找的数 i 来做比较
如果中间值在i的左边,那么证明中间值比i小了,这时候我们就要缩小范围,将左下标的值变成中间值的坐标+1——>left=mid+1 同理,当中间值在i的右边时,那么就要将右下标的值变成中间值-1——>right=mid-1
在这里还有一点注意的是计算数组长度的时候我们可以用(left+right)/2来计算,但这个不好的点在于可能会报错,如果我的left+right的值超过了最大值,系统就会报错。
所以在这里我们采用left+(right-left)/2是最好的
每次都要进行这样的判断,我们就想用循环来进行这样的判断。
while (left <= right)
{
int mid = (left + right) / 2;
//int mid=left+(right-left)/2 防止报错数字过大
if (arr[mid] < i)
{
left = mid + 1;
}
else if (arr[mid] > i)
{
right = mid - 1;
}
else
{
printf("找到了下标为:%d", mid);
break;
}
if(left>right)
printf("找不到");
}
当我们的中间值和我们要找的i值一样时,那我们就找到了,并且输出下标。
完整代码是这样的:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);//计算长度 strlen计算是不包含\0的
int left = 0;
int right = sz - 1;
printf("请输入一个数:");
scanf("%d", &i);
while (left <= right)
{
int mid = (left + right) / 2;
//int mid=left+(right-left)/2 防止报错数字过大
if (arr[mid] < i)
{
left = mid + 1;
}
else if (arr[mid] > i)
{
right = mid - 1;
}
else
{
printf("找到了下标为:%d", mid);
break;
}
if(left>right)
printf("找不到");
}
return 0;
}
让我们测试一下,比如我们要找数字7和数字14
数字7:
数字14:
这样就解决了我们的问题。
如果对你解决问题有帮助的话,点个赞再走吧~