zoukankan      html  css  js  c++  java
  • 二分搜索,呵呵

    二分搜索 呵呵


    写在前面的话:

    二分搜索原理看似都懂,但是真的让我敲起来,我还真不敢保证写的一定没有bug,甚至陷入bug里不知道怎么改呢.
    其实,二分法真的不是那么简单,尤其是二分的各个变种.下面一次介绍各种变种二分法,并且加上我的总结吧.

    1. 基本二分法

    在一个排好序的数组里查找一个key值.

    int search(int *arr, int n, int key)
    {
        int left = 0, right = n-1;
        while(left<=right) {
            int mid = left + ((right - left) << 1);
            if (arr[mid] == key) return mid; 
            else if(arr[mid] > key) right = mid - 1;
            else left = mid + 1;
        }
        return -1;
    }
    

    如果条件变化成, 数组中的数据可能重复,要求范围等于key值最小的下标,或者找出数组中第一个大于(或等于)key值的元素下标,请看下面

    2. 找出第一个与key相等的元素

    int searchFirstEqual(int *arr, int n, int key)
    {
        int left = 0, right = n-1;
        while(left<=right) {
            int mid = (left+right)/2;
            if(arr[mid] >= key) right = mid - 1;
            else if(arr[mid] < key) left = mid + 1;
        }
        if( left < n && arr[left] == key) return left;
        return -1;
    }
    

    3. 找出最后一个与key相等的元素

    int searchLastEqual(int *arr, int n, int key)
    {
        int left = 0, right = n-1;
        while(left<=right) {
            int mid = (left+right)/2;
            if(arr[mid] > key) right = mid - 1;
            else if(arr[mid] <= key) left = mid + 1; 
        }
        if( right>=0 && arr[right] == key) return right;
        return -1;
    }
    

    4. 找出第一个大于或等于key的元素

    int searchFirstEqualOrLarger(int *arr, int n, int key)
    {
        int left=0, right=n-1;
        while(left<=right) {
            int mid = (left+right)/2;
            if(arr[mid] >= key) right = mid-1;
            else if (arr[mid] < key) left = mid+1;
        }
        return left;
    }
    

    5. 找出第一个大于key的元素

    int searchFirstLarger(int *arr, int n, int key)
    {
        int left=0, right=n-1;
        while(left<=right) {
            int mid = (left+right)/2;
            if(arr[mid] > key) right = mid-1;
            else if (arr[mid] <= key) left = mid+1;
        }
        return left;
    }
    

    6. 找出最后一个小于或等于key的元素

    int searchLastEqualOrSmaller(int *arr, int n, int key)
    {
        int left=0, right=n-1;
        while(left<=right) {
            int m = (left+right)/2;
            if(arr[m] > key) right = m-1;
            else if (arr[m] <= key) left = m+1;
        }
        return right;
    }
    

    7. 找出最后一个小于key的元素

    int searchLastSmaller(int *arr, int n, int key)
    {
        int left=0, right=n-1;
        while(left<=right) {
            int mid = (left+right)/2;
            if(arr[mid] >= key) right = mid-1;
            else if (arr[mid] < key) left = mid+1;
        }
        return right;
    }
    

    我的总结:

    1. 各种二分有一些代码部分是不变的,记住就好.也很容易记住.
    int search(int *arr, int n, int key)
    {
        int left=0, right=n-1;
        while(left<=right) {
            int mid = (left+right)/2;
            if(arr[mid] /****/ key) right = mid-1;
            else if (arr[mid] /****/ key) left = mid+1;
        }
        return /****/;
    }
    

    其中除了3处/****/之外,其他部分可以说是模板,很简短,用的时候敲出来就行了
    2. 返回值问题:
    记住left和right是key值存在的范围. 所以当要找最后一个等于key时,必然返回right . 当要找最大的小鱼key值时, 必然返回left
    3. a[mid] == key 时, 到底是改变left还是right?
    这里要用 "不会更坏的"想法来理解比较好.
    比如,当我们知道要 返回值 和 条件是否包括等于 后,我们再来看等号如何处理.
    比如:条件包括等号,返回值为left . 那么就意味着不取等号那种情况后所做的操作不可以将left变化成mid+1,因为一旦这样变化,最终返回left的时候不再可能是mid,而mid是符合条件(包括等于)要求的 . 这肯定是不合理的.所以等号绝不是加在这里 .


    说到这里,我们的返回值和等号加在哪里,2个问题都解决了,就可以写完美的二分法啦!

  • 相关阅读:
    Markdown学习笔记
    带下划线点域名解析失败
    前端工程师学习之路
    Java 调用 WebService 客户端代码 含通过代理调用
    MySQL 日期函数 时间函数 总结 (MySQL 5_X)
    Apache、Tomcat整合环境搭建
    201671010142 <java程序设计>初次学习心得与感悟
    201671010142 Java基本程序设计结构学习的感悟
    201671010142.第五章的学习总结
    201671010142 继承定义与使用 感悟与总结
  • 原文地址:https://www.cnblogs.com/shawn-ji/p/5704314.html
Copyright © 2011-2022 走看看