zoukankan      html  css  js  c++  java
  • 难以理解的二分查找

    二分查找

    转载自朝夕大神

    方法一:

    
    //二分查找V0.1实现版
    //copyright@2011 July
    //随时欢迎读者找bug,email:zhoulei0907@yahoo.cn。
    
    //首先要把握下面几个要点:
    //right=n-1 => while(left <= right) => right=middle-1;
    //right=n   => while(left <  right) => right=middle;
    //middle的计算不能写在while循环外,否则无法得到更新。
    
    int binary_search(int array[],int n,int value)
    {
        int left=0;
        int right=n-1;
        //如果这里是int right = n 的话,那么下面有两处地方需要修改,以保证一一对应:
        //1、下面循环的条件则是while(left < right)
        //2、循环内当array[middle]>value 的时候,right = mid
    
        while (left<=right)          //循环条件,适时而变
        {
            int middle=left + ((right-left)>>1);  //防止溢出,移位也更高效。同时,每次循环都需要更新。
    
            if (array[middle]>value)
            {
                right =middle-1;   //right赋值,适时而变
            }
            else if(array[middle]<value)
            {
                left=middle+1;
            }
            else
                return middle;
            //可能会有读者认为刚开始时就要判断相等,但毕竟数组中不相等的情况更多
            //如果每次循环都判断一下是否相等,将耗费时间
        }
        return -1;
    }
    
    

    方法二:

    
    /* binsearch 寻找key下标,不存在 return -1 */
    
    /* binsearch 注意点【找不到 vs 死循环】
     * 1. left <= right 如改为 left < right 可能找不到key
     *    例如 1 2 3 4 5;key=5; left==right时候才搜到key
     * 2. left = mid + 1;
     *    如上left改为=mid,可能死循环,例如上面例子,
     *    当left指向4时候,right指向5,此时,死循环;
     *    死循环的根本原因在于left,当两个指针left与right相邻
     *    left可能永远等于mid,而right不会因为等于mid死循环
     */
    int binsearch(int * arr, int lef, int rig, int key)
    {
        if(!arr)    return -1;
        int left = lef, right = rig;
        while(left <= right)
        {
            int mid = left + ((right-left)>>1);
            if(arr[mid] < key)
            {
                left = mid + 1;
            }else if(arr[mid] > key)
            {
                right = mid - 1;
            }else
                return mid;
        }
        return -1;
    }
    
    /* binsearch_min 返回key(可能有重复)第一次出现的下标,如无return -1
     *
     * binsearch_min 注意点【死循环】
     * 1. 如果while(left < right)改为(left <= right)可能死循环;
     * 2. 循环结束条件,left == right
     *
     * 该代码我测试了很多用例,没发现反例,我认为是对的
     * 但网上都是用的left<right-1的条件并分别对arr[left]和arr[right]
     * 进行检查;我认为我写的更简练,希望有兴趣的读者帮忙review这段代码
     * 如发现反例指出错误,感激不尽,嘿
     */
    int binsearch_min(int * arr, int lef, int rig, int key)
    {
        if(!arr)    return -1;
        int left = lef, right = rig;
        while(left < right)
        {
            int mid = left + ((right-left)>>1);
            if(arr[mid] < key)
            {
                left = mid+1;
            }
            else
            {
                right = mid;
            }
        }
        if(arr[left] == key)    return left;
        return -1;
    }
    
    /* binsearch_max 返回key(可能有重复)最后一次出现的下标,如无return -1
     *
     * binsearch_max 注意点【死循环 vs 越过目标位置】
     * 1. 如果改为while(left < right)可能死循环;
     * 2. 如果left=mid改为left=mid+1;则有可能越过目标位置
     * 3. 循环结束条件,left == right || left == right -1
     *
     * 如非要死记:找最大的等号放<=key的位置,找最小的等号放>=key位置
     */
    int binsearch_max(int * arr, int lef, int rig, int key)
    {
        if(!arr)    return -1;
        int left = lef, right = rig;
        while(left < right -1)
        {
            int mid = left + ((right-left)>>1);
            if(arr[mid] <= key)
            {
                left = mid;
            }
            else
            {
                right = mid;
            }
        }
        if(arr[right] == key) // 找max,先判断right
        {
            return right;
        }
        else if(arr[left] == key)
        {
            return left;
        }else
            return -1;
    }
    
    /* binsearch_justsmall 返回刚好小于key的元素下标,如无return -1
     *
     * binsearch_justsmall 注意点【死循环 vs 越过目标位置】
     * 1. 如果改为while(left < right)可能死循环;因为left=mid的缘故
     * 2. 如果left=mid改为left=mid+1;则有可能越过目标位置
     * 3. 循环结束条件,left == right || left == right -1
     */
    int binsearch_justsmall(int * arr, int lef, int rig, int key)
    {
        if(!arr)    return -1;
        int left = lef, right = rig;
        while(left < right - 1)
        {
            int mid = left + ((right-left)>>1);
            if(arr[mid] < key)
            {
                left = mid;
            }else
            {
                right = mid - 1;
            }
        }
        if(arr[right] < key) // 找刚好小于,先判断right
        {
            return right;
        }else if(arr[left] < key)
        {
            return left;
        }else
            return -1;
    }
    
    /* binsearch_justgreat 返回刚好大于key的元素下标,如无return -1
     *
     * binsearch_justgreat 注意点【死循环 vs 检查元素是否大于key】
     * 1. 如果改为while(left <= right)可能死循环;因为right = mid;
     * 2. 最后注意检查arr[right]是否大于key
     * 3. 循环结束条件,left == right
     */
    int binsearch_justgreat(int * arr, int lef, int rig, int key)
    {
        if(!arr)    return -1;
        int left = lef, right = rig;
        while(left < right)
        {
            int mid = left + ((right-left)>>1);
            if(arr[mid] <= key)
            {
                left = mid + 1;
            }else
            {
                right = mid;
            }
        }
        if(arr[right] > key) return right;
        return -1;
    }
    
    
    
  • 相关阅读:
    Crazypony四轴飞行器代码框架
    Python中 sys.argv[]的用法简明解释
    详解STM32的PWM输出及频率和脉宽(占空比)的计算——寄存器配置六步曲!(转)
    jquery——所有版本下载
    jsop跨域请求方式--及中文乱码解决方案
    js ---任何浏览器关闭当前网页的代码
    jquery ajax跨域请求 IE9及以下不支持---调试
    poi---Excel导入数据-ClassNotFoundException
    ajax获取json数据为undefined--原因解析
    可变参数 / 枚举--详解
  • 原文地址:https://www.cnblogs.com/fzuljz/p/5701277.html
Copyright © 2011-2022 走看看