二分查找

 

       比如我今天想写一个二分查找:

       首先,很容易的写下 int bSearch(int begin, int end, int e)

       然后,很自然的定义 int mid, left = begin, right = end;

       接下来怎么写呢?while(left < right)?while(left <= right)?while(mid == left)?while(mid == right)?………………真正一个写程序人会想纠结好一会儿,我们就选一个吧while(left < right)

       下面,也很自然,mid = (left + right) >> 1; 用位运算能节省一些时间呢!

        现在呢?又是纠结的时候了吧?if(num[mid] > e)?if(num[mid] >= e)?我们也随便选一个吧,if(num[mid] > e)

        其实,下面你会不断纠结……right = mid;这是正常人的写法,但是有时候也会看到别人写成right = mid - 1;我们也考虑下吧,但是现在我们就直接写right = mid;

        有if了当然也会有else,然后理所当然 left = mid;同样记住还有一个选择left = mid + 1;

不错,整个while循环搞定了,最后就是返回了,写下return的时候是不是又纠结了?left?right?mid?算了,就写mid吧,整个程序就写好了,如下:

 1 int bSearch(int begin, int end, int e)
 2 {
 3     int mid, left = begin, right = end;
 4     while(left < right)
 5     {
 6         mid = (left + right) >> 1;
 7         if(num[mid] > e) right = mid;
 8         else left = mid;
 9     }
10     return mid;
11 }

  呵呵呵呵呵。。。。。。。。。。。。。。

--------------------------------------我是吐槽和正解的分割线----------------------------------------------

其实吧二分查找这个东西我们真的忽略太多了。。。也只有当我写主席树的时候貌似才真正注意到不同给跪。。。

我简单结合一下STL中的lower_bound()谈谈理解:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cstring>
 7 #define PAU putchar(' ')
 8 #define ENT putchar('\n')
 9 using namespace std;
10 int A[100];
11 int find1(float v){
12     int L=0,R=7,M;
13     while(L<=R){
14         M=L+R>>1;if(A[M]<v) L=M+1;else R=M-1;
15     } return L;
16 }
17 int find2(float v){
18     int L=0,R=7,M;
19     while(L<R){
20         M=L+R>>1;if(A[M]<v) L=M+1;else R=M;
21     } return L;
22 }
23 int find3(float v){
24     int L=0,R=7,M;
25     while(L<=R){
26         M=L+R>>1;if(A[M]<v) L=M+1;else R=M-1;
27     } return R+1;
28 }
29 int find4(float v){
30     int L=0,R=7,M;
31     while(L<R){
32         M=L+R>>1;if(A[M]<v) L=M+1;else R=M;
33     } return R;
34 }
35 int find5(float v){
36     int L=0,R=7,M;
37     while(L<=R){
38         M=L+R>>1;if(A[M]>v) R=M-1;else L=M+1;
39     } return L;
40 }
41 int find6(float v){
42     int L=0,R=7,M;
43     while(L<R){
44         M=L+R>>1;if(A[M]>v) R=M;else L=M+1;
45     } return L;
46 }
47 int find7(float v){
48     int L=0,R=7,M;
49     while(L<=R){
50         M=L+R>>1;if(A[M]>v) R=M-1;else L=M+1;
51     } return R+1;
52 }
53 int find8(float v){
54     int L=0,R=7,M;
55     while(L<=R){
56         M=L+R>>1;if(A[M]>v) R=M-1;else L=M+1;
57     } return R+1;
58 }
59 inline int read(){
60     int x=0,sig=1;char ch=getchar();
61     while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();}
62     while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
63     return x*=sig;
64 }
65 inline void write(int x){
66     if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
67     int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;
68     for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
69 }
70 void init(){
71     A[0]=5;
72     A[1]=5;
73     A[2]=6;
74     A[3]=6;
75     A[4]=6;
76     A[5]=9;
77     A[6]=9;
78     A[7]=10;
79     float cv=6;
80     write(find1(cv));ENT;
81     write(find2(cv));ENT;
82     write(find3(cv));ENT;
83     write(find4(cv));ENT;
84     write(lower_bound(A,A+8,cv)-A);ENT;
85     write(find5(cv));ENT;
86     write(find6(cv));ENT;
87     write(find7(cv));ENT;
88     write(find8(cv));ENT;
89     write(upper_bound(A,A+8,cv)-A);ENT;
90     return;
91 }
92 void work(){
93     return;
94 }
95 void print(){
96     return;
97 }
98 int main(){init();work();print();return 0;}

这是我写的十个简单的查找的函数。

事实证明,这十个查找函数竟然全都是正确的,其中前五个返回了第一个重复的值,后五个返回了最后一个重复的值的地址+1。

至于速度,find1,2,5,6最快,STL最慢。

取左还是右,在于if()后面跟的是什么操作。

事实上,二分查找的变形还有许许多多。So,真正二分还是很神奇的,OI建议使用find1,移动光标速度会很快。(雾)

最后把主席树扔上来。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=100000+10,maxnode=2000000+10;
 7 int ls[maxnode],rs[maxnode],s[maxnode],root[maxn],A[maxn],num[maxn],ms,n,Q;
 8 int find(int v){
 9     int L=1,R=n,M;
10     while(L<=R){
11         M=L+R>>1;if(num[M]<v) L=M+1;else R=M-1;
12     } return L;
13 }
14 void build(int x,int& y,int L,int R,int pos){
15     s[y=++ms]=s[x]+1;if(L==R)return;
16     ls[y]=ls[x];rs[y]=rs[x];int M=L+R>>1;
17     if(pos<=M) build(ls[x],ls[y],L,M,pos);
18     else build(rs[x],rs[y],M+1,R,pos); return;
19 }
20 int query(int x,int y,int L,int R,int k){
21     if(L==R) return L;
22     int M=L+R>>1,kth=s[ls[y]]-s[ls[x]];
23     if(k<=kth) return query(ls[x],ls[y],L,M,k);
24     else return query(rs[x],rs[y],M+1,R,k-kth);
25 }
26 inline int read(){
27     int x=0,sig=1;char ch=getchar();
28     while(!isdigit(ch)){if(ch=='-') sig=-1;ch=getchar();}
29     while(isdigit(ch)) x=10*x+ch-'0',ch=getchar();
30     return x*=sig;
31 }
32 inline void write(int x){
33     if(x==0){putchar('0');return;}if(x<0) putchar('-'),x=-x;
34     int len=0,buf[15];while(x) buf[len++]=x%10,x/=10;
35     for(int i=len-1;i>=0;i--) putchar(buf[i]+'0');return;
36 }
37 void init(){
38     n=read();Q=read();for(int i=1;i<=n;i++) num[i]=A[i]=read();
39     sort(num+1,num+1+n);for(int i=1;i<=n;i++) build(root[i-1],root[i],1,n,find(A[i]));
40     return;
41 }
42 void work(){
43     int a,b,c;
44     while(Q--){
45         a=read();b=read();c=read();
46         write(num[query(root[a-1],root[b],1,n,c)]);
47         putchar('\n');
48     }
49     return;
50 }
51 void print(){
52     return;
53 }
54 int main(){
55     init();work();print();return 0;
56 }

 

posted @ 2015-05-14 00:32  AI_Believer  阅读(497)  评论(0编辑  收藏  举报