二分模版
非递归时,貌似效率最高,数据小时效率差不多!
非递归模板:
int search(int a[], int n, int v) //这个好像是效率最高的 { int left = -1, right = n, middle; while(left+1 != right) { middle = left + (right-left) / 2; if(a[middle] < v) left = middle; else right = middle; } if(right >= n || a[right] != v) right = -1; return right; }
递归模板:
#include <stdio.h> #include <string.h> int a[1000001]; int Binsearch(int a[],int s,int t,int key) { int low=s; int high=t; int mid; if(s<=t) { mid=low+(high-low)/2; if(a[mid]==key) { return mid; } else if(a[mid]>key) { return Binsearch(a,low,mid-1,key); } else { return Binsearch(a,mid+1,high,key); } } return -1; } int main() { int n,i,key; while(scanf("%d",&n)!=EOF) { for(i=0; i<n; i++) scanf("%d",&a[i]); scanf("%d",&key); int t=Binsearch(a,0,n-1,key); if(t==-1) printf("NO\n"); else printf("YES\n"); } return 0; }
2.改进二分查找--若查找的元素出现多次查找第一次出现的位置
我们可以从第一次得代码中知道,上述代码不能确定查找到得元素的位置为第一次出现的位置。怎么确定查找的元素在该序列中出现的是第一次呢,我们举一个例:
数组:1 2 3 3 3 3 3 5 ;8个元素,查找值为3的元素。
将数组分为两个子段(0+7)/2 = 3: 1 2 3 3 3 3 3 5
此时已查找到3,一种简单的实现方法可以在从该位置开始向前搜索,找到直到不等于3的时候就停止,这个时候找到3的位置就是第一次出现的位置,同理我们也可以用这种方法找到最后出现的3的位置。
语法:result=search_bin(int *t,int k,int n); |
|
参数: |
|
t[]: |
待查找数组 |
k: |
查找关键字 |
n: |
数组元素个数 |
返回值: |
如果k在t[]中存在,输出i,i为k在t[]中第一次出现的位置:t[i]=k,否则输出-1 |
注意: |
数组元素从0开始存储 |
|
要求查找数组是有序升序序列 |
源程序: |
|
|
int search_bin(int *t,int k,int n) { while(t[mid] != k) { mid--; } return mid+1; } else if (k<t[mid]) high=mid-1; |
我们通过上面的代码也许可以知道,这样实现确实很简单,但是这样效率确实降低了,如果有一个极端的例子,即一个数组里面的元素全部相同,且我们要查找的元素就是该数组的元素此时在查找第一个出现位置的时候就比较消耗时间,这里我们可以深入一点,继续利用分治的方法查找它第一次出现的位置。
示例:数组:1 2 3 3 3 3 3 5 ;8个元素,查找值为3的元素。
将数组分为两个子段(0+7)/2 = 3: 1 2 3 3 3 3 3 5
在查找到元素后记录该位置flag ,由于搜索的是第一次出现的位置,所以 应该搜索左子数组,调整搜索上界为mid-1,即为high=2;
在此范围内继续进行二分查找,实际上就是在查找到元素的时候并不停止搜索,而是继续搜索直到搜索子数组不存在。
语法:result=search_bin(int *t,int k,int n); |
|
参数: |
|
t[]: |
待查找数组 |
k: |
查找关键字 |
n: |
数组元素个数 |
返回值: |
如果k在t[]中存在,输出i,i为k在t[]中第一次出现的位置:t[i]=k,否则输出-1 |
注意: |
数组元素从0开始存储 |
|
要求查找数组是有序升序序列 |
源程序: |
|
|
int search_bin(int *t,int k,int n) int flag = -1; { flag = mid; high = mid-1; //如果查找最后一次出现的位置 //low = mid + 1;; } if(flag == -1) else return flag; |
测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int cmp ( const void *a , const void *b )
{
return *(int *)a - *(int *)b;
}
int search_bin(int *t,int k,int n){
int low=0,high=n-1,mid;
int flag = -1;
while (low<=high)
{
mid=(low+high)/2;
if (k==t[mid])
{
flag = mid;
high = mid-1;
//如果查找最后一次出现的位置
//low = mid + 1;;
}
else if (k<t[mid]) high=mid-1;
else low=mid+1;
}
if(flag == -1)
return -1;
else
return flag;
}
int main(int argc, char **argv)
{
int array[100];
int i,j;
int p[2];
int key;
srand(time(0));
for(i = 0; i< 100; i++)
{
array[i] = rand()%100;
}
qsort(array,100,sizeof(array[0]),cmp);
for(i = 0; i< 10; i++)
{
for(j=0; j<10; j++)
{
printf(" %d ", array[i*10+j]);
}
printf("\n");
}
while(1)
{
printf("key : ");
scanf("%d", &key);
p[0] = search_bin(array,key,100);
printf("%d \n",p[0]);
}
return 0;
}
程序结果:
0 1 1 3 3 4 5 5 6 7
7 7 8 9 9 9 12 14 15 15
16 19 19 20 20 21 21 24 26 26
26 27 30 31 32 34 34 34 34 35
35 36 37 37 37 38 39 39 39 39
39 39 42 43 44 45 45 47 51 51
51 52 53 55 55 55 55 56 56 58
58 63 63 66 67 68 68 70 71 71
74 75 77 77 78 82 84 84 85 85
85 86 89 90 90 93 94 94 97 99
key : 3
3
key : 5
6
key : 9
13
key : 0
0
key : 1
1
key :
3.改进二分查找--若查找的元素未出现则返回出现的中间位置
在之前的二分查找中都没有考虑没有查找到关键字时返回该关键字应该位于数组哪个位置的情况,而是直接考虑的是返回失败,二分查找是在查找的时候是利用的是中间位置与关键值的大小比较,当查找失败的时候,查找到得位置也就当前最接近关键值的位置,且这样找到的关键值的位置是第一场出现的位置。我们可以利用这个特性来查找到关键值的位置。我们还是用一个例子来说明该种情况:
示例:如有已排序数组有8个元素如下查找元素x = 3;
1 5 6 7 9 10 12 44
将数组分为两个子段(0+7)/2 = 3: 1 5 6 7 9 10 12 44
Array[3] = 7 > x=3,继续查找,high = mid -1; mid = 1;
此时array[1] = 5 > x = 5,继续查找, high = mid-1; mid = 0;
此时array[0] = 1 < x = 5,继续查找 high = 0, low = 1,失败退出,此时mid = 0,为最接近关键值的值,通过比较可以得出。
语法:void search_bin(int *t,int k,int n, int p[2]); |
|
参数: |
|
t[]: |
待查找数组 |
k: |
查找关键字 |
n: |
数组元素个数 |
int p[2] |
p[0]代表关键值下界,p[1]代表关键值上界 |
返回值: |
无 |
注意: |
数组元素从0开始存储 |
|
要求查找数组是有序升序序列 |
源程序: |
|
|
void search_bin(int *t,int k,int n, int p[2]) int flag = -1; { flag = mid; break; } if(flag == -1) if(t[mid] > k) { p[0] = mid-1; p[1] = mid; } else { p[0] = mid; p[1] = mid+1;
} } else { p[0] = p[1] = flag ;
} |
测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int cmp ( const void *a , const void *b )
{
return *(int *)a - *(int *)b;
}
void search_bin(int *t,int k,int n, int p[2])
{
int low=0,high=n-1,mid;
int flag = -1;
while (low<=high)
{
mid=(low+high)/2;
if (k==t[mid])
{
flag = mid;
break;
}
else if (k<t[mid])
high=mid-1;
else low=mid+1;
}
if(flag == -1)
{
if(t[mid] > k)
{
p[0] = mid-1;
p[1] = mid;
}
else
{
p[0] = mid;
p[1] = mid+1;
}
}
else
{
p[0] = p[1] = flag ;
}}
int main(int argc, char **argv)
{
int array[100];
int i,j;
int p[2];
int key;
srand(time(0));
for(i = 0; i< 100; i++)
{
array[i] = rand()%100;
}
qsort(array,100,sizeof(array[0]),cmp);
for(i = 0; i< 10; i++)
{
for(j=0; j<10; j++)
{
printf(" %d ", array[i*10+j]);
}
printf("\n");
}
while(1)
{
printf("key : ");
scanf("%d", &key);
search_bin(array,key,100,p);
printf("%d %d\n",p[0],p[1]);
}
return 0;
}
程序结果:
3 3 7 7 7 8 9 10 11 11
12 14 14 18 19 19 21 21 22 22
23 24 26 26 27 28 28 29 29 29
33 33 34 35 35 36 36 38 39 41
41 41 41 43 46 50 50 53 53 54
54 55 56 56 57 58 58 59 60 60
64 64 65 66 68 69 71 71 71 71
72 72 73 74 77 77 78 80 80 82
82 82 83 84 84 85 85 86 87 87
88 89 90 91 92 93 94 95 98 99
key : 3
0 0
key : 7
2 2
key : 100
99 100
key :
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; int n,m,t; int a[100001]; void er(int a[],int lf,int rf,int key) { int l=lf,mid; int r=rf; while(l<=r) { mid = l+(r-l)/2; if(a[mid]==key) { t=mid; r=mid-1; } else if(a[mid]>key) { r=mid-1; } else { l=mid+1; } } return ; } int main() { while(scanf("%d",&n)!=EOF) { for(int i=0; i<n; i++) { scanf("%d",&a[i]); } //sort(a,a+n); scanf("%d",&m); t=-1; er(a,0,n-1,m); printf("t==%d\n",t); if(t!=-1) printf("YES\n"); else printf("NO\n"); } return 0; }