zoukankan      html  css  js  c++  java
  • 二分查找小结

    参考资料:

         1、程序员编程艺术第二十五章
         2、勇幸的博客
    二分查找除了参考以下代码外,参考lower_bound()upper_bound()两个函数的实现代码

    • 资料一的代码
    //二分查找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;
    }
    
    
  • 相关阅读:
    PAT 1097. Deduplication on a Linked List (链表)
    PAT 1096. Consecutive Factors
    PAT 1095. Cars on Campus
    PAT 1094. The Largest Generation (层级遍历)
    PAT 1093. Count PAT's
    PAT 1092. To Buy or Not to Buy
    PAT 1091. Acute Stroke (bfs)
    CSS:word-wrap/overflow/transition
    node-webkit中的requirejs报错问题:path must be a string error in Require.js
    script加载之defer和async
  • 原文地址:https://www.cnblogs.com/ZhaoxiCheung/p/5692395.html
Copyright © 2011-2022 走看看