【算法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 排版

posted @ 2021-05-30 11:45  白缺  阅读(119)  评论(0编辑  收藏  举报