zoukankan      html  css  js  c++  java
  • 二分

    二分是个很实用的算法,每次运算区间均缩小一半,因此时间复杂度是logN

    下面给出简约版二分算法:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e6+7;
     4 int n,m,l,arr[maxn];
     5 int find(int x)
     6 {
     7     int mid;
     8     int left=-1;///开始坐标-1;
     9     int right=n;///结束坐标+1;
    10     while(left+1<right)
    11     {
    12         mid=(left+right)/2;
    13         if(arr[mid]<=x)
    14             left=mid;
    15         else
    16             right=mid;
    17     }
    18     return right;
    19 }
    20 int main()
    21 {
    22     scanf("%d",&n);
    23     for(int i=0;i<n;i++)
    24         scanf("%d",&arr[i]);
    25     for(int i=0;i<n;i++)
    26          printf("%d %d
    ",arr[i],find(arr[i]));
    27 }

    其中判断的结果产生的效果为:找到一个大于x的第一个位置(返回right);找到一个小于等于x的第一个位置(返回left);

    问题1: 为什么不写成 left=mid+1和right=mid-1 ?

      因为有可能arr[mid]已经是极限值。若执行right=mid-1的话,极限值的位置就被跳过了,从而导致出错。

    举个例子:

      设arr[]={0 1 3 4,5}  求找到大于2的第一个位置

      当right=5left=-1;   则mid=2; A[mid]>2;

      因此若r=mid-1=1就导致出错。

    问题2:为什么不写成 While(left!=right) ?

      因为上面的原因我们没用 left=mid+1right=mid-1而是left=mid,right=mid。因此就会出现死循环的情况。

    举个例子:

      arr[]={0,1,3,4}; 求找2的位置时会出现问题

      当left=1right=2时 mid=(left+right)/2=1; arr[mid]<2; 所以left=mid=1

      结果left还是等于1right还是等于2。死循环...

     代码解析:

    原代码中left代表小于等于 x的一方 right代表大于x的一方

    我们每次判断mid是属于left还是属于right来使区间缩小一半;

    leftright相遇时,即left+1=right分界线就在leftright中间

    则从left开始往前小于等于x,right开始往后大于x

    同理其实我们也可以让

    Iff(mid)<x

           left=mid;

    else

           right=mid;

    left代表小于x的一方而right代表大于等于x的一方

    leftright相遇时;

    则从left开始往前小于x,right开始往后大于等于x

     

  • 相关阅读:
    用指针方法排序数组
    struct和typedef struct
    结构体类型定义的一般式
    HDOJ1020 Encoding
    malloc函数详解
    新手入门 acm 输入输出练习
    【算法入门】广度/宽度优先搜索(BFS)
    C++栈和队列
    hdu畅通工程
    codevs 2639 约会计划
  • 原文地址:https://www.cnblogs.com/ashen137/p/10348888.html
Copyright © 2011-2022 走看看