搜索之线性搜索和二分搜索

   今天介绍下搜索的方法,其实对于今天介绍的两种搜索方式是很简单的,尤其是线性搜索,但是本着完整性的心态,还是不想把搜索这章中两种简单的方法漏掉,那就稍微简单介绍下吧。

注意:本博文介绍的搜索都是不含重复元素的搜索,至于重复下的搜索,只需用到另外一个数据结构用来存放这多个重复元素的下标就行了,就不多作介绍。

1.线性搜索

  线性搜索看名字就看出来了,是最简单的搜索方式,顾名思义,就是从头到尾一个个查找搜索,其基本的算法模式如下:


LinearSearch()
   for(i从0到n-1)
     if(A[i]与key相等)    
       return i;
 return Not_Found;



 其实可以看到就是一个简单的for循环,但是就是这么简单的算法,也有优化的地方,这也许就是算法的魅力所在。

 其优化的方面在于判断次数的优化,这里我们可以看到,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:从写上一篇博文的大年初三后忙着走亲戚,聚会啥,耽误了学习和博客,更新慢了~虽然目前也没人看我的这个系列博客,但是我还是要自己监督自己~


  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值