• 关于二分查找和二分搜索


    首先是二分查找,举个有序的整数数组例子(二分查找和搜索都是针对有序数组)

     public int rank(int key, int n) {
            int lo = 0, hi = n - 1;
            while (lo <= hi) {
                int mid = lo + ((hi - lo) >> 1); //>>1是除以2
                // 为什么不直接(lo+hi)>>1呢,因为lo+hi可能溢出,而hi-lo不溢出,lo+(hi-lo)>>1是小于hi的,也不溢出,更安全
                int cmp = key - a[mid];// a为有序数组
                if (cmp < 0) {
                    hi = mid - 1;
                } else if (cmp > 0) {
                    lo = mid + 1;
                } else {
                    return mid;
                }
            }
            return lo;
        }

    如果查找到,返回数组下标mid,如果没找到,return lo;有人会问了为什么返回lo??当然你非要在找不到的情况下返回一个负数比如-1也可以。这就是关键所在,假设a[10]={1, 2, 5, 7, 7, 12, 13, 17, 18, 20};我要查找的key是6。

    第一步:lo   hi   mid

                 0     9     4        

                 0     3     1        a[4]=7 > key=6,所以hi=mid - 1=3;    lo=0  <=  hi=3继续循环,mid=(lo+hi)/2=1

                 2     3     2        cmp = 6-a[1] > 0,所以lo=mid+1=2,lo=2  <=  hi=3继续循环,mid=(lo+hi)/2=2

                 3     3     3        cmp = 6-a[2] > 0,所以lo=mid+1=3,lo=3  <=  hi=3继续循环,mid=(lo+hi)/2=3

                 3     2               cmp = 6-a[3] < 0,所以hi=mid-1=2, 此刻不满足套件,跳出,返回lo=3

        返回3什么意思?你看看这个数组,是不是小于6有3个元素?

            lo的值正好等于数组中小于被查找的元素的数量

             那怎么知道有没有找到呢?返回的到底是命中的下标还是小于被查找元素数量呢? 

                用  i=rank(key, n); // 在n个元素的数组查找key=6,返回下标传给i

                     if (i<n&&a[i] == key){表示找到了}

                          else  {没找到}

                   一些有序集合判断,如果集合包含这些元素,就更新数值,if(i<n&&a[i] == key){更新数值}。或者要插入的位置在哪里?假如lo=5,我查找一遍,就知道他前面有5个元素,即我这次要插入的元素下标就为5(从0开始计算)


    下面讲一下二分搜索

    比如从有序数组中查找某个数值

                                                                                    lower_bound

        给定长度为n的单调不下降数列a0, a1,...an-1和一个数k,求满足aik条件的最小的i。不存在的情况输出n。

     限制条件

     1≤n106

       0a0a1...an-1<109

       0k109

       输入

       n = 5

       a = {2, 3, 3, 5, 6}

       k = 3

      输出

        1(其中a0<3, a1>=3)

      这里不仅仅是二分查找了,不仅是找到下标,而是找到最小的下标

      直接上代码(关键部分)

       int n, k;
        int[] a = new int[1000001];
        public void solve() {
            int lo = 0, hi = n;
            while (hi > lo) {
                int mid = lo + ((hi - lo) >> 1);
                if (a[mid] >= k) {
                    hi = mid;
                } else {
                    lo = mid;
                }
            }
            System.out.println(hi);// 最后hi和lo一样,就算找不到的情况返回n,这种情况下lo=hi=n,返回哪个都一样
        } 
    

    比如a[5]={2, 3, 3, 5, 6}

    a[2]=3和3进行比较,可以知道解不大于2

    a[1]=3和3比较,可以知道解不大于1

    a[0]=2和3比较,可以知道解不小于0

    所以解为1

    二分搜索法是通过不断缩小解的可能存在的范围,从而求得问题最优解的方法。

    ========================================Talk is cheap, show me the code=======================================


    CSDN博客地址:https://blog.csdn.net/qq_34115899
  • 相关阅读:
    c语言学习指针变量
    SQL字符串函数
    [转]HttpWebRequest使用注意(发生阻塞的解决办法)
    Image.FormFile的锁文件解决
    不联网在win8安装framework3.5
    metro app损坏,修复以及商店速度慢的解决方法
    关于C#使用来电通的来电通内部原理浅析
    winform模拟qq聊天界面的小功能textbox1输入自动跳到textbox2
    C#下的路由器后台登录
    dropbox文件夹路径丢失变回默认文件的解决方法
  • 原文地址:https://www.cnblogs.com/lcy0515/p/9179810.html
Copyright © 2020-2023  润新知