二分查找的用处
在⼀个有序的数组中查找指定的数字n,很容易想到的方法就是遍历数组,但是这种方法效率比较低。
例如:
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int k = 7;
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0])
for(i = 0;i < sz; i++)
{
if(arr[i] = k)
{
printf("找到了,下标是%d\n",i);
break;
}
}
if(i == sz)
{
printf("找不到\n");
}
return 0;
}
这样遍历会很慢,比如我买了⼀双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?你会1,2,3,4...这样猜吗?显然很慢;⼀般你都会猜中间数字,比如:150,然 后看大了还是小了,这就二分查找,也叫折半查找。
二分查找的原理图解
例如,在有序数组arr[]={0,1,2,3,4,5,6,7,8,9,10}中查找7
初始状态:
第一轮查找:根据(left+right)/2 = 4,下标4的位置是5,5<7所有可以判定 7 位于 5 右侧的区域,更新搜索区域为元素 5 右侧的区域。
第二轮查找:根据(left+right)/2 = 7,下标7的位置是8,8>7所有可以判定 7 位于 8 左侧的区域,更新搜索区域为元素 8 左侧的区域。
第三轮查找: 根据(left+right)/2 = 5,下标5的位置是6,6<7所有可以判定 7 位于 6 右侧的区域,更新搜索区域为元素 6 右侧的区域。
第四轮查找: 搜索区域内中间元素的位置是 [(6+6)/2]=6,因此中间元素是 7,此元素就是要找的目标元素
代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//左边界下标
int left = 0;
//右边界下标
int right = sizeof(arr) / sizeof(arr[0]) - 1;
//要找的数字
int key = 7;
//记录中间元素的下标
int mid = 0;
int find = 0;
// 当左边界还未超过右边界时,进行二分查找
while (left <= right)
{
mid = (left + right) / 2;// 每次循环重新给mid赋值,改变中间值的下标
// 如果中间值大于目标值,说明目标值在左半边,此时改变右边界的下标(缩减右半边)
if (arr[mid] > key)
{
right = mid - 1;
}
// 如果中间值小于目标值,说明目标值在右半边,此时改变左边界的下标(缩减左半边)
else if (arr[mid] < key)
{
left = mid + 1;
}
// 如果都不满足,说明查找成功,此时跳出循环
else
{
find = 1;
break;
}
}
if (1 == find)
printf("找到了,下标是%d\n", mid);
else
printf("找不到\n");
}
求中间元素的下标,使用 mid = (left+right)/2 ,如果left和right比较大的时候可能存在问题,可以使用下面的方式:
mid = left+(right-left)/2;
感谢各位读者的观看。