对于我们现在所学的知识,在一个数组中寻找关键数或者关键字符很容易,但是很多acmer在oj上永远都是wa或者超时,让人焦头烂额啊!!!
最简单的查找方式就是暴力求解,说白了就是从头遍历到尾,运气好的话就是第一个(如果是这样,你去玩彩票去吧),运气不好的话,嘿嘿,你知道n有多大嘛?
首先我们先探讨暴力求解和二分查找的时间复杂度吧
1.暴力求解
在一个数组中,如果采用遍历的方式去寻找关键字,则需要从i=0(或者i=1,这个根据个人习惯)开始遍历,知道找到关键字返回下标值,否则从头遍历到尾,我们做最坏的打算就是n了。也就是说暴力求解的时间复杂度为o(n)。
2.二分查找
我们现在假定有一个数组a[6]={1,5,3,7,4,8},其n=6,假如我们需要查找的数字key=8,二分顾名思义就是一分为二嘛,所以说我们可以把数组拆成两半,怎么拆嘞,容旺仔小胜娓娓道来。
因为n=6,所以我们可以定义一个变量mid(中间的意思),即mid=n/2,由此可以算出mid=3,然后将a[mid](a[3])与key进行比较,假如比key小,就说明key正在数组的右半部分,反之(到这里还能理解吧???),在这里我教大家怎么去用代码实现(部分伪代码)
int a={1,5,3,7,4,8}
int l=1;
int r=6;
int ans=-1;
int mid;
int key=8;
while(l<=r)
{
mid=(l+r)/2;
if(a[mid]==key)
{
ans=mid;
break;
}
if(a[mid]>key)
{
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;//得出关键字的下标索引值
看这里,代码中可能引入了一些新的变量,l,r分别表示的是数组的最左边和最右边的下标索引值,当确定关键数组在那一半时,则要确定那一半为一个新的数组,舍弃另一半的数组,所以会出现为啥会有r=mid-1或者l=mid+1(为啥是这个,留给自己琢磨一下吧!!!)
我们再来算算时间复杂度吧,通俗点,一半的一半的一半......不就是反复除以二嘛???就好像n,反复去除以2最终等于1,反过来推就2^x=n,即x=,这样看来,是不是时间上少了很多。
要睡觉了,就写到这里吧,完整代码就在下面!!!
#include<iostream>
using namespace std;
const int N=1e6;
int arr[N];
int binarysearch(int arr[],int n,int x)
{
int l=1;
int r=n;
int ans=-1;
int mid;
while(l<=r)
{
mid=(l+r)/2;
if(arr[mid]==x)
{
ans=mid;
break;
}
if(arr[mid]>x)
{
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;
}
int main()
{
int n,key,ans;
cin>>n>>key;
for(int i=1;i<=n;i++)
cin>>arr[i];
ans=binarysearch(arr,n,key);
cout<<ans<<endl;
return 0;
}