折半查找的一些注意事项

int search0(int *vec, int N, int key)
{
	int lo = 0, hi = N - 1, mid;

	while (lo <= hi) {			// 注意点1
		mid = lo + (hi - lo) / 2;// 注意点2
		if (key == vec[mid])
			return mid;
		else if (key < vec[mid])
			hi = mid - 1;		// 注意点3
		else
			lo = mid + 1;		// 注意点3
	}

	return -1;
}

    注意点1:不能用lo < hi做判断条件,因为无法处理区间只包含一个元素的情况。出现这种情况,可能的原因有两种,一是原始序列就只包含一个元素,二是在逐步逼近的过程中,产生了只包含一个元素的区间。

    注意点2:这个用法比mid=(lo+hi)/2安全。

    注意点3:每次进入while循环,搜索的是[lo,hi]这个双闭区间。当本次未找到,则说明mid这个位置已经被搜索过,是不符合要求的。而进入下半区或上半区时,如果用[lo,mid]或[mid,hi],则mid位置被重复搜索。当区间只包含一个元素时,会导致死循环。

    上面这个基本的二分查找算法,未找到时,循环内需要做两次比较操作。可以稍作修改,使比较次数减少为一次。

int search1(int *vec, int N, int key)
{
	int lo = 0, hi = N - 1, mid;

	while (lo <= hi) {
		mid = lo + (hi - lo) / 2;
		if (key < vec[mid])
			hi = mid - 1;
		else
			lo = mid + 1;
	}

	if (lo > 0 && key == vec[lo - 1])
		return lo - 1;

	return -1;
}

    由于二分查找的效率已足够高(每次减半,区间缩小很快),就某次查找来说,第二种方法提升的效率不明显,而且没有第一种方法好理解,所以通常还是使用第一种方法。

    未找到时,lo,hi还有一个额外的作用(上面两种方法都适用),lo指向大于指定值的最近位置(可能超出上端);hi指向小于指定值的最近位置(可能超出下端)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值