今天介绍下搜索的方法,其实对于今天介绍的两种搜索方式是很简单的,尤其是线性搜索,但是本着完整性的心态,还是不想把搜索这章中两种简单的方法漏掉,那就稍微简单介绍下吧。
注意:本博文介绍的搜索都是不含重复元素的搜索,至于重复下的搜索,只需用到另外一个数据结构用来存放这多个重复元素的下标就行了,就不多作介绍。
1.线性搜索
线性搜索看名字就看出来了,是最简单的搜索方式,顾名思义,就是从头到尾一个个查找搜索,其基本的算法模式如下:
LinearSearch()
for(i从0到n-1)
if(A[i]与key相等)
return i;
return Not_Found;
其优化的方面在于判断次数的优化,这里我们可以看到,for循环中每次变量i变化时,要进行两次的比较,首先是i与数组边界n的比较和A[i]和key的比较。
我们优化的方法就是设置一个标记,一个有个特殊值的元素,借助这种编程技巧,我们能达到简化循环控制等诸多目的。在线性搜索中,我们吧标记放在数组的末尾,其具体的实现方法如下:
LinearSearch()
i=0;
A[n]=key;
while(A[i]与key不相等)
i++;
f(i达到了n)
return Not_Found;
return i;
key为要搜索的值,将key插入末尾,这样在下标从0~n的元素中,可能有两个位置的元素等于key,(要注意的是,0~n-1菜蔬数组的有效范围,A[n]是标记)这样从头开始遍历比较,不等则i++比较下一个,因为最终A[n]=key,所以能保证的是while肯定是会结束的,但是重点就是while循环是在哪里结束退出循环的,如果在i=n退出时,那说明之前的0~n-1并没有元素只等于key,那么说明原来的数组的有效范围内找不到该值。反之,当退出循环时,i不等于n,则说明在有效范围找到了该值。这样的话,每次for循环中i变化时,只需要进行一次A[i]与key的比较就行了,最后再加一次i与n的比较就行。(这里是我平时没有注意到的,也是算法深深吸引我的地方,优中求优) 线性搜索的时间复杂度为O(n),但是在引用了标记后效率可以提升常数倍,在处理大规模数据时会有比较明显的效果。
2.二分搜索
二分搜索又叫二分查找,其看名字就可以想到该算法的实现步骤,就是每次将有效的查找范围分为两半,并且每次将范围减少一半,其中每次通过将要查找的值key与有效范围中间的值比较来判断是否已经找到该值,或者需要在剩下的哪一半中继续查找。其基本的源代码如下:
int Binary_search(int a[],int n,int key)
{
int start=0,end=n,mid; //end指向搜索范围中最后一个元素的后一个位置
while(start<end)
{
mid=(start+end)/2;
if(a[mid]==key) return mid;
if(key>a[mid]) start=mid+1;
else end=mid; //注意::在key<a[mid],有效范围为start~mid-1,所以这里en置为mid,
}
return -1;
}
但是要注意的一点是,在进行二分查找之前,必须保证元素是有序排列的,这样才能根据要查找的值key与中间值的比较结果来判断需要在哪一半继续查找或者查找结束。
举个例子,比如对于已知的数组1 2 3 4 5 6 7 8 ,想要查找7的位置,那么一开始start=0,end=8,第一次查找mid=(start+end)/2=4,找到A[4]=5,这时在元素已经升序排列的情况下,那么肯定可以得到7的位置在当前中间位置4之后,所以将start置为4+1=5,这时有效范围为下标从5到8,然后继续去中间位置A[(5+8)/2]=A[6]=7,这时找到该值,返回位置6.至于不存在该值时,由于不存在,那么永远不会有A[mid]==key,那么就不会返回return mid,这样的户,while不断循环,必然导致start不断变大或者end不断变小,当start>=end时,就退出循环,这时便说明找到不到该值。
其实二分查找有很多细节方面的注意点,比如上面的一种二分查找就是将end初始化为数组元素的最后一个位置的后一个位置,当然也可以将end=n-1,那么就有了以下的源代码:
int start=0,end=n-1; //end指向搜索范围中最后一个元素的位置
int mid=(start+end)/2;
while(end>=start && a[mid]!=key)
{
cout<<"start="<<start<<" mid="<<mid<<" end="<<end<<endl;
if(a[mid]>key) end=mid-1;
else start=mid+1;
mid=(start+end)/2;
}
if(end>=start)
return mid;
else
return -1;
当然还有递归形式下的二分法,就不介绍了,总之知道二分原理就行,而且在实际比赛和开发中我们也并不需要自己从头写二分查找,STL中有很多方法,具体可以参考:STL中与二分查找有关的四个函数
PS:从写上一篇博文的大年初三后忙着走亲戚,聚会啥,耽误了学习和博客,更新慢了~虽然目前也没人看我的这个系列博客,但是我还是要自己监督自己~