二分板子
二分板子
Description
用有序表表示静态查找表时,通常检索函数可以用折半查找来实现。
折半查找的查找过程是:首先确定待查记录所在的范围,然后逐步缩小范围直到找到或者确定找不到相应的记录为止。而每次需要缩小的范围均为上一次的一半,这样的查找过程可以被称为折半查找。
其查找过程可以描述如下:
![](https://img2018.cnblogs.com/i-beta/1592233/201911/1592233-20191129121217369-394361428.png)
在本题中,读入一串有序的整数,另外给定多次查询,判断每一次查询是否找到了相应的整数,如果找到则输出整数相应的位置。
Input
输入的第一行包含2个正整数n和k,分别表示共有n个整数和k次查询。其中n不超过1000,k同样不超过1000。
第二行包含n个用空格隔开的正整数,表示n个有序的整数。输入保证这n个整数是从小到大递增的。
第三行包含k个用空格隔开的正整数,表示k次查询的目标。
Output
只有1行,包含k个整数,分别表示每一次的查询结果。如果在查询中找到了对应的整数,则输出其相应的位置,否则输出-1。
请在每个整数后输出一个空格,并请注意行尾输出换行。
Sample Input
8 3 1 3 5 7 8 9 10 15 9 2 5
Sample Output
5 -1 2
HINT
在本题中,需要按照题目描述中的算法完成折半查找过程。通过将需要查询的值与当前区间中央的整数进行比较,不断缩小区间的范围,直到确定被查询的值是否存在。
通过课本中的性能分析部分,不难发现折半查找的时间复杂度为O(log2n),这是一种非常高效的查找方法。
如果序列为单调递增序列:
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 #include <stack> 11 #include <map> 12 #include <sstream> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 const int mod=1e9+7; 16 const int maxn=1e5+10; 17 using namespace std; 18 19 int a[1005]; 20 21 int main() 22 { 23 int n,m; 24 scanf("%d %d",&n,&m); 25 for(int i=0;i<n;i++) 26 scanf("%d",&a[i]); 27 for(int i=0;i<m;i++) 28 { 29 int x; 30 scanf("%d",&x); 31 int l=0; 32 int r=n-1; 33 int mid; 34 int flag=0; 35 while(l<=r) 36 { 37 mid=(l+r)>>1; 38 if(a[mid]==x) 39 { 40 flag=1; 41 break; 42 } 43 else if(a[mid]>x) 44 r=mid-1; 45 else 46 l=mid+1; 47 } 48 if(flag==1) 49 printf("%d ",mid); 50 else 51 printf("-1 "); 52 } 53 printf("\n"); 54 return 0; 55 }
递归写法:
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 #include <stack> 11 #include <map> 12 #include <sstream> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 const int mod=1e9+7; 16 const int maxn=1e5+10; 17 using namespace std; 18 19 int a[maxn]; 20 21 int Find(int L,int R,int x) 22 { 23 if(L>R) //查找失败 24 return -1; 25 int mid=(L+R)/2; 26 if(a[mid]==x) //找到直接返回 27 return mid; 28 else if(a[mid]>x) //大于待找元素则往左区间找 29 return Find(L,mid-1,x); 30 else //小于待找元素则往右区间找 31 return Find(mid+1,R,x); 32 } 33 34 int main() 35 { 36 int n;//元素个数 37 scanf("%d",&n); 38 for(int i=1;i<=n;i++)//保证元素递增有序 39 scanf("%d",&a[i]); 40 int x;//待查元素 41 scanf("%d",&x); 42 int L=1,R=n;//初始化边界 43 int ans=Find(L,R,x); 44 if(ans==-1) 45 printf("查找失败\n"); 46 else 47 printf("%d\n",ans); 48 return 0; 49 }
如果序列为单调非递减序列(有重复值):
#include <stdio.h> #include <string.h> #include <iostream> #include <string> #include <math.h> #include <algorithm> #include <vector> #include <queue> #include <set> #include <stack> #include <map> #include <sstream> const int INF=0x3f3f3f3f; typedef long long LL; const int mod=1e9+7; const int maxn=1e5+10; using namespace std; int a[1005]; int main() { int n,m; scanf("%d %d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<m;i++) { int x; scanf("%d",&x); int l=0; int r=n-1; int mid; while(l<r) { mid=(l+r)>>1; if(a[mid]<x) l=mid+1; else r=mid; } if(a[l]==x) printf("%d ",l); else printf("-1 "); } printf("\n"); return 0; }
在非递减序列中插入x
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 #include <stack> 11 #include <map> 12 #include <sstream> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 const int mod=1e9+7; 16 const int maxn=1e5+10; 17 using namespace std; 18 19 int a[maxn]; 20 21 void Insert(int L,int R,int x,int (&a)[maxn],int n)//在元素个数为n的a[L,R]中插入X 22 { 23 int pos=n;//待插位置初始化为n 24 while(L<=R) 25 { 26 int mid=(L+R)/2; 27 if(a[mid]<x) 28 L=mid+1; 29 else 30 { 31 pos=mid; 32 R=mid-1; 33 } 34 } 35 for(int i=n;i>pos;i--)//腾位置 36 { 37 a[i]=a[i-1]; 38 } 39 a[pos]=x;//插入 40 } 41 42 int main() 43 { 44 int n;//元素个数 45 printf("请输入元素个数:"); 46 scanf("%d",&n); 47 printf("请输入这些元素:\n"); 48 for(int i=0;i<n;i++)//保证元素为非递减序列,可以有重复值 49 scanf("%d",&a[i]); 50 int x;//待插入元素 51 printf("请输入待插入的元素:"); 52 scanf("%d",&x); 53 int L=0,R=n-1;//初始化边界 54 Insert(L,R,x,a,n);//插入 55 printf("插入后序列为:\n"); 56 for(int i=0;i<=n;i++) 57 { 58 printf("%d ",a[i]); 59 } 60 printf("\n"); 61 return 0; 62 }