编程基础之二分查找——剖析

作者:admin|日期:2019-01-27|热度:

算法介绍

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列

原理分析

一、精确查找:
每次取中点元素进行比较(把序列分成左右两个部分),如果相等即查找结束(如果有多个相同结果的,可能要求输出最小或是最大的值,需另做处理);否则如果太大,那说明结果在左边序列里面,在左边继续查找;如果太小,那说明结果在右边序列里面,在右边继续查找;如果中点不存在,即查找失败(结束)。

二、模糊查找:
每次取中点元素进行比较(把序列分成左右两个部分),如果相等即查找结束(如果有多个相同结果的,可能要求输出最小或是最大的值,需另做处理);否则如果太大,那说明结果在左边序列里面,在左边继续查找;如果太小,那说明结果在右边序列里面,在右边继续查找;如果中点不存在,即查找结束,输出左右两个中最接近的一个。
比如:NOI 01:查找最接近的元素
代码实例:

#include <iostream>
#include <cmath>
using namespace std;
int find(int d[],int x,int l,int r){
int m;
if(l==r) return d[l];
if(r-l==1){
return abs(d[l]-x)<=abs(d[r]-x)?d[l]:d[r];
}
m=(r+l)/2;
if(x==d[m]){
return d[m];
}else if(x>d[m]){
return find(d,x,m,r);
}else{
return find(d,x,l,m);
}
}
int main()
{
int n,m,d[100001],x;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>d[i];
}
cin>>m;
for(int i=0;i<m;i++){
cin>>x;
cout<<find(d,x,0,n-1)<<endl;
}
return 0;
}

三、查找最优解:
先确定解的最小和最大值,然后每次取中点去检查,看是否通过,直到中点不存在,输出结果。
比如:NOI 04:网线主管(切网线)
先确定一个最小值(肯定可以)和一个最大值(肯定不可以),那么结果一定在最小值和最大值之间,再采用二分查找不断取中点测试,如果可以,说明结果有可能更大(在右边),否则说明结果应该更小(在左边),当中点不存在的时候,查找结束,那么左边的值就是最优解。
代码实例:

#include <iostream>
#include <cmath>
using namespace std;

int N,K;
int wx[10001];

int cut(int n)
{
int x=0,y;
for(int i=0;i<N;i++)
{
y=wx[i]/n;
if(y>=1) x+=y;
if(x>=K) break;
}
return x;
}

int findx(int min,int max)
{
if(max-min<=1) return min;
int mid=(min+max)/2;
int x=cut(mid);
if(x>=K) return findx(mid,max);
if(x<K) return findx(min,mid);
}

int main()
{
int max=0,min=0;
float w;
cin>>N>>K;
for(int i=0;i<N;i++)
{
cin>>w;
wx[i]=w*100;
max=wx[i]>max?wx[i]:max;
min=wx[i]<min?wx[i]:min;
}
min=min/(K/N+1);
if(cut(max)>=K) w=max/100.0;
else{
int y=findx(min,max);
w=y/100.0;
}
printf("%.2f",w);
return 0;
}