二分查找
二分查找算法
二分查找算法是在有序数组中用到的较为频繁的一种算法,在未接触二分查找算法时,最通用的一种做法是,对数组进行遍历,跟每个元素进行比较,其时间为O(n).但二分查找算法则更优,因为其查找时间为O(lgn),譬如数组{1, 2, 3, 4, 5, 6, 7, 8, 9},查找元素6,用二分查找的算法执行的话,其顺序为:
1.第一步查找中间元素,即5,由于5<6,则6必然在5之后的数组元素中,那么就在{6, 7, 8, 9}中查找,
2.寻找{6, 7, 8, 9}的中位数,为7,7>6,则6应该在7左边的数组元素中,那么只剩下6,即找到了。
二分查找算法就是不断将数组进行对半分割,每次拿中间元素和goal进行比较。
模板程序:
#include <iostream>
using namespace std;
//二分查找
int binary_search(int* a, int len, int goal);
int main()
{
const int LEN = 10000;
int a[LEN];
for (int i = 0; i < LEN; i++)
a[i] = i - 5000;
int target = 0;
int index = binary_search(a, LEN, target);
if (index != -1)
cout<<target<<"在数组中的下标为"<<index<<endl;
else
cout<<"不存在"<<target<<endl;
return 0;
}
int binary_search(int* a, int len, int goal)
{
int low = 0;
int high = len -1;
while (low <= high)
{
int middle = (high - low) / 2 + low; // 直接使用(high + low) / 2 可能导致溢出
if (a[middle] == goal)
return middle;
//在左半边
else if (a[middle] > goal)
high = middle - 1;
//在右半边
else
low = middle + 1;
}
//没找到
return -1;
}
转自:NULL
例题一:
查找最接近的元素
总时间限制: 1000ms 内存限制: 65536kB
描述
在一个非降序列中,查找与给定值最接近的元素。
输入
第一行包含一个整数n,为非降序列长度。1 <= n <= 100000。
第二行包含n个整数,为非降序列各元素。所有元素的大小均在0-1,000,000,000之间。
第三行包含一个整数m,为要询问的给定值个数。1 <= m <= 10000。
接下来m行,每行一个整数,为要询问最接近元素的给定值。所有给定值的大小均在0-1,000,000,000之间。
输出
m行,每行一个整数,为最接近相应给定值的元素值,保持输入顺序。若有多个值满足条件,输出最小的一个。
样例输入
3
2 5 8
2
10
5
样例输出
8
5
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int l,r,mid;
int a[100001];
int ta,I,m,n,i,flag;
int main()
{
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for (I=1;I<=m;I++)
{
scanf("%d",&ta); //ta为目标
l=1;
r=n+1;
flag=0;
while (l+1<r)
{
mid=(l+r)/2;
if (a[mid]>ta)
r=mid;
else if (a[mid]<ta)
l=mid;
else if (a[mid]==ta)
{
flag=1;
printf("%d\n",a[mid]);
break;
}
}
if (flag==0)
{
if (abs(a[r]-ta)<abs(a[l]-ta))
{
if (r==n+1)
printf("%d\n",a[r-1]);
else printf("%d\n",a[r]);
}
else printf("%d\n",a[l]);
}
}
}
例题二:
二分法求函数的零点
总时间限制: 1000ms 内存限制: 65536kB
描述
有函数:
f(x) = x5 - 15 * x4+ 85 * x3- 225 * x2+ 274 * x - 121
已知 f(1.5) > 0 , f(2.4) < 0 且方程 f(x) = 0 在区间 [1.5,2.4] 有且只有一个根,请用二分法求出该根。
输入
无。
输出
该方程在区间[1.5,2.4]中的根。要求四舍五入到小数点后6位。
样例输入
无
样例输出
不提供
这是二分查找中比较经典的一类题,就是求一个函数在某一区间的根。
#include<iostream>
#include<cstdio>
using namespace std;
double mid,x;
double hs(double x)
{
return x*x*x*x*x-15*x*x*x*x+85*x*x*x-225*x*x+274*x-121;
}
int main()
{
double l=1.5,r=2.4;
while (r-l>0.0000001)
{
mid=(l+r)/2.0;
x=hs(mid);
if (x<0) r=mid;
else l=mid+0.0000001;
}
printf("%.6lf",mid);
}