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

    归纳

    • 优点:比较次数少、查找速度快、平均性能好
    • 缺点:待查找表为有序表、插入删除困难
    • 时间复杂度:O(logN)
    • 实用场景:有序数组

    思路

    假设表为升序排列,中间元素和待查元素比较,如果中间元素和待查元素相等找到了;如果小于则在前半段找;否则在后半段找。

    递归

    int BiSearch(int *a, int begin, int end, int value)
    {
        if (a == NULL || begin > end)
             return -1;
        if (end >= begin)
        {
            int mid = (begin + end) / 2;
            if (a[mid] == value)
                return mid;
            else if(a[mid] > value)
                return BiSearch(a, begin, mid-1, value);
            else
                return BiSearch(a, mid+1, end, value);
        }
        return -1;
    }    

    迭代

    int BiSearch(int *a, int len, int value)
    {
        if (a == NULL && len <= 0)
              return -1;
        int beg = 0, end = len-1; 
        while (end >= begin)
        {
            int mid = (begin + end) / 2;
            if (a[mid] == value)
                return mid;
            else if(a[mid] > value)
                end = mid - 1;
            else
                begin = mid + 1;
        }
        return -1;
    }        

    案例一

    在有序数组1 2 3 3 3 3 4 5中3出现的次数为4,1出现的次数为1。

    分析:有序数组查找——二分查找。二分找到被查找的元素,再两边扩展,直到找全为止。

    参考代码

    #include <iostream>
    using namespace std;
    int findMinSpan(int *a, int beg, int end, int val)
    {
        if (beg > end)
            return 0;
        else
        {
            int mid = beg + (end - beg) / 2;
            if (a[mid] == val)
            {
                int count = 1;
                for (int i = mid-1; i >= beg; --i)
                {
                    if (a[i] == val)
                        ++count;
                    else
                        break;
                }
                for (int i = mid+1; i <= end; ++i)
                {
                    if (a[i] == val)
                        ++count;
                    else
                        break;
                }
                return count;
            }
            else if (val < a[mid])
                return findMinSpan(a, beg, mid-1, val);
            else
                return findMinSpan(a, mid+1, end, val);
        }
    }
    
    int MultiNum(int *a, int size, int val)
    {
        if(a == NULL || size <= 0)
            return 0;
        int span = findMinSpan(a, 0, size-1, val);
        return span;
    }
    
    int main()
    {
        int a[] = {1, 2, 3, 3, 3, 3, 4, 5};
        int val = 3;
        int size = sizeof(a) / sizeof(*a);
        cout << MultiNum(a, size, val) << endl; //4
    }

    案例二

    求旋转数组的最小元素(把一个数组最开始的若干个元素搬到数组的末尾,称之为数组的旋转。输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1)

    思路:有序数组——二分查找。

    1 2 3 4 5 6   红底为中间位置元素,绿色为四个元素(a[beg] a[mid-1] a[mid+1], a[end])中的最小值
    2 3 4 5 6 1
    3 4 5 6 1 2
    4 5 6 1 2 3
    5 6 1 2 3 4
    6 1 2 3 4 5

    中间位置是mid,把数组分成左右两部分

    左部分的最小值left = min(a[beg], a[min-1])

    右部分的最小值right=min(a[mid+1], a[end])

    • 如果a[mid]最小,则最小值为a[mid]
    • 如果left最小,则最小值在beg~mid-1
    • 如果right最小,则最小值在mid+1~end

    参考代码

    int findMin(int *a, int len)
    {
        if (a == NULL || len <= 0)
           return -1;
        int beg = 0, end = len-1, mid;
        while (beg <= end)
        {
            if (a[beg] < a[end] || beg == end)
               return beg;
            if (beg + 1 == end)
               return a[beg] < a[end] ? beg : end;
            mid = beg + (end - beg) / 2;
            if (a[beg] <= a[mid])
               beg = mid;
            else
                end = mid;
        }
    }

    测试

    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    int findMin(int *a, int len)
    {
        if (a == NULL || len <= 0)
           return -1;
        int beg = 0, end = len-1, mid;
        while (beg <= end)
        {
            if (a[beg] < a[end] || beg == end)
               return beg;
            if (beg + 1 == end)
               return a[beg] < a[end] ? beg : end;
            mid = beg + (end - beg) / 2;
            if (a[beg] <= a[mid])
               beg = mid;
            else
                end = mid;
        }
    }
        
    int main()
    {
        int a[] = {1, 2, 3, 4, 5};
        int len = sizeof(a) / sizeof(int);
        cout << findMin(a, len) << endl;
        
        int b[] = {2, 3, 4, 5, 1};
        len = sizeof(b) / sizeof(int);
        cout << findMin(b, len) << endl;
        
        int c[] = {3, 4, 5, 1, 2};
        len = sizeof(c) / sizeof(int);
        cout << findMin(c, len) << endl;
        
        int d[] = {4, 5, 1, 2, 3};
        len = sizeof(d) / sizeof(int);
        cout << findMin(d, len) << endl;
        
        int e[] = {5, 1, 2, 3, 4};
        len = sizeof(e) / sizeof(int);
        cout << findMin(e, len) << endl;
        
        int f[] = {5};
        len = sizeof(f) / sizeof(int);
        cout << findMin(f, len) << endl;
        system("pause");
    }

     

  • 相关阅读:
    去除Html标签
    asp.net弹出多个模态窗口
    window.returnValue的用法
    eTerm-用于报价的指令(GK状态码的使用)
    使用ffmpeg 操作音频文件前后部分静音移除.
    使用Visual Studio 2017开发python,并在iis上部署Python Django
    解决wampserver 服务无法启动
    网站优化记录-通过命令预编译Asp.net 网站,成功优化到毫秒级别。
    Scut游戏引擎改造兼容Codis。
    windows修改Host后未生效。
  • 原文地址:https://www.cnblogs.com/kaituorensheng/p/3550151.html
Copyright © 2011-2022 走看看