排序的重要意义之一,就是为检索带来方便。
对于小白面对,问题:n个整数,从这n个整数中查找是否含有520。最容易想到的方法是把他们放到数组中去然后依次检查这些整数是否等于520,这样对于n比较小的数来说很好,但是n一旦过于大,就需要把整个数组遍历好多次,会白白增加运行时间。
而二分查找法的出现就可以更快的查找到你想要的数据。
二分查找用于有序表中查找数据。通过逐步缩小数据范围来进行查找。
尽管二分法可以用递归实现,但是一般还是写成非递归形式。
注意:
对与有序表可以直接使用二分查找:
例如:(oj上的题)
描述
在一个非降序列中,查找与给定值最接近的元素。
输入
第一行包含一个整数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>
using namespace std;
int num[100009];
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>num[i]; //把有序表输入到数组中。
}
int m,k,l,r,mid;
cin>>m;
for(int i=1;i<=m;i++){
cin>>k;
l=0; //二分查找的下界
r=n-1; //上界
while(l+1<r){ //确保下界小于上界
mid=(l+r)/2; //中间数
if(num[mid]>k){ //判断查找数的范围
r=mid; //通过更新上界的数值来缩小数据范围
}
else {
l=mid; // 通过更新下界的数值来缩小数据范围
}
}
if(num[r]-k<k-num[l]){
cout<<num[r]<<endl;
}
else{
cout<<num[l]<<endl;
}
}
return 0;
}
对于无序表可以先试用sort函数把数据进行排列成有序表,然后在使用二分查找。
mid的值还有一种写法:
int mid = left + ((right - left) >> 1);//此处的mid的计算一定要放在while循环内部,否则mid无法正确更新;并且此处用移位代替除以2可以提高效率,而且可以防止溢出。
“ >> 是右移运算,在计算机中是一种运算操作,但是他的运算结果正好能对应一个整数的二分之一值,这就正好能代替数学上的除2运算,但是比除2运算要快。”