一,搜索,查询的方式
当我们要查询某一个固定的值的时候,我们首先首先想到的是一个基础的朴素遍历思想,就是对全部的内容都进行遍历一整遍的遍历,这种方法无疑是能够完成这种遍历的,但是这种方式的时间复杂度高达O(n),这个时间复杂度对多次查找的操作是相当的不友好的,众所周知,O(n2) 在数据范围比较大的情况下都是会爆时间的,所以我们要思考一种更加简便的方法,来简化一下这个操作。
当这个数据存在一定的顺序关系的时候,我们可以用这个所谓的关系来比较大小,划定他所存在的区间,这样每次我们都能少遍历一半的数据,所以我们叫这个搜索办法为二分查找。本质的意义就是为这个值逐步划定范围,从而确定这个值的解。
二,二分算法的实现过程
1,二分的思考
二分搜索在向这个目标值缩短区间这是非常明显的,但是如何这个目标是存在好几个相同的数值的一个区间呢,我们二分算法的两种写法就会产生区别,在这里我喜欢用前二分查找和后二分查找来叫他们,他们只有在这个目标值存在多个的时候会返回不同的数值,在不存在目标值或者说目标值为一个的时候返回是相同的操作
目标值不为1个的例子
当然二分查找还有比较重要的一点是:二分查找的操作的数值之间是要有顺序关系的,不要仅仅局限于大小关系.
2,代码实现过程
首先我们看一下我们二分算法需要导入的数据,
int bsearch_1(int l ,int r, int x)
//l:最开始的下标 ,r:是最结尾的下标 x :是查找的数值
当完成这步骤的时候我们要进行二分的查找操作
1.前二分搜索
while (i < j)
{
int mid = (l + r) >> 1 ;
//中间值mid 前搜就是最简单的 l + r
if(q[mid] >= x) r = mid ;
else l = mid + 1 ;
//前搜要控制后面的值为 = 就是 r = mid
}
2.后二分搜索
while(i < j)
{
int mid = l + r + 1 >> 1;
if(q[mid] <= x ) l = mid ;
else r = mid - 1 ;
}
完成搜索操作之后,我们要检验一下这个值到底是不是我们要求的这个值
if(q[r] != x)
return - 1;
//当搜索不到的时候返回 - 1 ;
else
return r; //搜索的最后 r == l
3 ,总代码
#include <iostream>
const int N =100010;
int n , m ,q[N] ;
int bsearch_1(int l ,int r ,int x)
{
while (l < r)
{
int mid = r + l >> 1;
if(q[mid] >= x ) r = mid ;
else l = mid + 1 ;
}
if(q[l] != x )
return - 1 ;
else return l;
}
int bsearch_2 (int l ,int r ,int x )
{
while (l < r)
{
int mid = (l + r + 1 ) >> 1 ;
if(q[mid] <= x) l = mid ;
else r = mid - 1;
}
if(q[l] != x )
return - 1 ;
else return l ;
}
//两搜索的差别就是一个前查找,另一个为后查找
using namespace std;
int main ()
{
cin >> n >> m;
for(int i = 0 ; i < n ; i ++ )
cin >> q[i];
while ( m -- )
{
int n1;
cin >> n1 ;
cout << bsearch_1( 0 , n - 1 , n1 )<<" "<<bsearch_2( 0 , n - 1 , n1 )<<endl;
}
return 0;
}