一、前言
二分查找好在哪?
我举个例子在5000个数里面找数字2500,无论事正序找反序找,我们都得找2500次,而二分查找最多只需要以2为底对整个数的个数取对数就行(log)。
二分查找也同样有很多细节要注意。
二、二分查找的思路
例如一组数1,2,3,4,5,6,7,8,9,10;想得到的目标数是7,只需要算出整组数的一头一尾的平均数,跟目标数比较大小就行,一次次将范围缩小。如果平均数比目标数大,就从头到平均数-1的数重新计算平均数;如果平均数比目标数小,则相反。
三、用代码写出来这样的思路
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int binary_search(int arr[],int k,int sz)
{
int left = 0;
int right = sz-1;
while (left<=right)//循坏的条件是一个很重要的细节
{
int mid = (left + right) / 2;
if (arr[mid] > k)
{
right = mid - 1;
}
else if (arr[mid] < k)
{
left = mid + 1;
}
else
{
return mid;
}
}
return -1;//与主函数的判断语句达成很妙的作用
}
int main()
{
int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
int sz = sizeof(arr) / sizeof(0);//
int k = 10;
int ret=binary_search(arr, k, sz);
if (ret!=-1)
{
printf("找到了,下标是%d\n", ret);
}
else
{
printf("找不到\n");
}
return 0;
}
while循环的条件left<=right很关键的,例如数列1,2,3,4,5,6,8,9,10在其中找7,你按这个算法永远没有结果,在后续计算后数组下标的顺序还进行了交换。
return -1还有数组找不到的情况,最后得到返回值-1就是找不到的情况。
四、语句中的细节
a.数组是在主函数计算好大小后传参的。
因为数组传参实际上是传过去的首元素的地址,sz的值为1。
为什么传参是传过去的首元素的地址?
——有位大佬讲过:“形参只是实参的一份临时拷贝。”如果数组足够大,你拷贝一份数组就会造成大量的内存浪费,所以计算机大部分数组传参是传过去的首元素地址。
b.有许多野生彭于晏就要问了,为什么整个数组没有传过去,在自定义函数里面能够找得到并进行打印?
指针‘arr’指向数组的起始地址,而‘arr[mid]’实际上是在该地址上加上‘mid’以得到,‘mid’个元素的地址,然后从那个地址取值,在binary_search函数中写‘arr[mid]’,它实际上访问的是数组中第’mid’个元素。
欢迎大家指出错误