查找操作------折半查找(二分查找)

对于无序的序列,可以使用排序来对序列中的元素排列从而使序列呈升序或降序列.而对这样一个有序的序列来讲,进行顺序查找就显得不合时宜了.那么在序列元素有序排列的情况下,应该如何实现排序呢?

以在图书馆查找需要的图书为例,当获得需要的图书编号后,就可以在书架上查找这本书了,此时,是将书架上的书一本本地翻看查找,还是放到一本书的编号后,跳过一部分书在查找呢?显然,大部分人都会选择后者.

这种查找方法就是所谓的"折半查找"(Binary Search).

折半查找的核心是查找一次就将查找的范围减掉一半.实现方式则是将目标与序列正中间的记录进行比较,如果相等,则查找成功;如果目标小于中间点,则将查找范围缩小到中间点前面;如果目标大于中间点,则将查找范围缩小到中间点后面半个序列.

下面为折半查找的代码实现.

int list::BinarySearch_1(const int target,int &position)//二分查找
{
	int top = count;//把上限和下限设置好
	int bottom = 0;
	while(bottom < top){
		int mid = (top + bottom) / 2;//设置中间点
		if(data[mid] < target)
			bottom = mid + 1;
		else
			top = mid;
	}
	if(top < bottom)
		return overflow;
	else{
		position = bottom;
		if(data[position] == target)
			return success;
		else
			return overflow;
	}
}

仔细分析过后,发现上述查找方法每次查找后将范围缩小一半,以此类推,直到最后将查找范围缩小到一个元素.此时如果剩下的元素与待查元素相等,则查找成功,否则失败.因此,其成本为logn.这里n为表中的个数.

但上面的查找方法没有考虑到也许某一次跟中间元素进行比较时出现相等的情况,也就是说中间点元素就是要查找的元素,此时查找已经成功,无需再进行折半.一个"改进"的查找方法如下.

int list::BinarySearch_2(const int target.int &position)
{
	int top = count;//把上限和下限设置好
	int bottom = 0;
	while(bottom < top){
		int mid = (top + bottom) / 2;//设置中间点
		if(data[mid] == target)		//中间点元素等于目标元素,查找成功
		{
			position = mid + 1;
			return success;
		}
		else if(data[mid] < target)//中间点元素小于目标元素,将查找范围缩小到右边半个表
			bottom = mid + 1;
		else						//中间点元素大于目标元素,将查找范围缩小到左边半个表
			top = mid - 1;
	}
	return overflow;
}

改进后的查找方法成本在最坏情况下,仍需要缩小到最后一个元素,而达到最后一个元素的过程中,每次需要进行两次比较。因此,在最坏情况下,这个方法的成本更高。在最好的情况下,则第一次比较久命中,成本为常数,好于改进前的方法。在平均情况下,即被查找的元素处于任意位置概率相等,则改进hoist的方法有(logn/2n+1/n)的概率好于改进前的方法,而不如改进前方法的概率为(1-logn/2n-1/n)。显然,随着n的增大,(logn/2n+1/n)将不断减小,而(1-logn/2n-1/n)则不断增大。也就是说,改进后的方法随着n的增大,将越来越不如改进前的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值