【算法1-4】二分查找
二分查找的含义
二分查找又称为折半查找,比如这里有个1~100的随机数,你来猜,一般人都会先猜50,如果这个随机数比50小,下一个就猜25,如果比25小,那在下一个就是12或者13。反正无论如何我就猜他是这一堆数里面的最中间的哪一个。
这里大家就会发现,二分查找是有两个条件的,一是数列有序,二是序列使用顺序储存结构(如数组)。
二分查找的原理和代码
最简单也是最本质的二分查找其实就是猜数字了,当然我这里还可以举个例子:现在这里有升序排列的10个数字,其中有个数字是5,求出5在这个序列中排第几个?
先取10的一半即5,取第五位数字,看看这个数字比5大还是小,如果是大的话,因为是升序排列,第五位之后的包括第五位数字都不可能是5,可以不去理会,所以现在这个要查找的序列就变成了从第一位到第四位数字了。就这样一直折半查找,直到求出答案。
看到这里,大家有些人会觉得直接遍历不就好咯,但是折半查找毕竟每次都把要查找序列消减了一半,如果题目给出的是n个数字的话,那么遍历的时间复杂度是o(n),而二分查找的时间复杂度是O(log2(n)),在n较大的情况下二分查找无疑是比遍历要快很多很多的(平均时间来看)。
题目给出n个已经升序排列的数字,对于每次询问(总共t次询问),求出值为m的数字排在第几位,如果没有m这个数字,则输出-1,主要代码如下:
int n, t, s[100007];
scanf("%d %d", &n, &t);
for (int i = 0; i < n; i++)
scanf("%d", &s[i]);
for (int i = 0; i < t; i++)
{
int m, mid = n/2, min = 0, max = n-1;
scanf("%d", &m);
while(s[mid] != m && max > min)
{
if (s[mid] > m)
max = mid - 1;
else
min = mid + 1;
mid = (max + min)/2;
}
if (s[mid] == m)
printf("%d\n", mid+1);
else
printf("-1\n");
}
关于二分查找的一点想法
想到二分查找,我在想如果有一串没有排序的数字,我要求值为m的数字在这堆数里面排行第几(即第几大)。
我可以先用sort()
函数把这串数字快排一下,再用二分查找来算m排行第几。
当然快排其实感觉上和二分查找其实有点类似,所以不如干脆一边快排一边查找,在快排中的每次将比mid大的分到一边,比它小的分到另一边,这时候只需比较mid是大于还是小于m,然后就可以把其中大的或者小的那一边给舍去掉了。就这样一直折半,直到mid == m
时,这时候mid排行老几,m就排行老几。
具体的快排结合查找的代码就不写出来了,大家可以自己思考一下,如果不清楚快排的可以看我之前写的关于简单快排的公众号推文。
当然其实很多时候,比较难一点的二分查找,它的形式一般都比较特别一点,但是本质上,都是有个max最大值,min最小值,mid中间值可以进行二分查找算法的,这个其实还不是很好讲,因为每道题有每道题的变化,但是本质上的max,min,mid代表的查找序列还是在的。
大家有兴趣的可以看看这道题,其实不是很难,但是给我们看到了二分查找是如何在题目中出现。P1873 砍树https://www.luogu.com.cn/problem/P1873。
这几天其实都不是很想学习,在又不想学习,又不想打游戏的情况下,我发现写文章就可以一直写下去的,也不会感觉很烦躁。就挺好的,嘿嘿。
本文使用 markdown.com.cn 排版