静态查找之有序表查找——二分查找、插值查找、斐波那契查找

静态查找之有序表查找——二分查找、插值查找、斐波那契查找

二分查找

二分查找又称折半查找,是有序查找算法的一种,即查找的序列必须是递增或递减的。它的原理类似于猜1至100中的任意数字,比如我们猜数字27,如果我们按顺序猜的话需要27次,如果随机猜的话,次数无法保证,可能很少也可能很多,我们按照这种方式猜,我们先猜中间数100/2=50,发现大了,我们再猜1至50的中间数50/2=25,发现小了,再猜25至50中间数(25+50)/2=37(取整),照此规律猜7次便可猜中27,使用这种方法猜1至100中任意数字不会超过7次。下面我们按照这种方法查找{1,3,20,24,44,67,71,82,90,110} 序列(length=10)中的数字71,在这里插入图片描述
首先我们先定义三个游标分别指向头(top)尾(end)和中间值(mid)。第一次我们将top=0,end=9(length-1),mid=[(0+9)/2]=4。
在这里插入图片描述
mid=4指向44小于71,我们取序列中大于44的部分继续查找。我们将top=mid+1=5,end不变。
在这里插入图片描述
取mid=[top+end]/2=7,mid=7指向82大于71,我们令end=mid-1,top不变。
在这里插入图片描述
取mid=[top+end]/2=5,mid=5指向67小于71,令top=mid+1,end不变。
在这里插入图片描述
取mid=[top+end]/2=6。mid=6指向71,查找成功,返回。
综上所述编程逻辑如下:

  1. 初始化top=0,end=length-1;
  2. 取mid=[top+end]/2,若mid指向查找值,成功返回;若mid指向值大于查找值则指向步骤3,否则指向步骤4;
  3. 令end=mid-1,执行步骤2;
  4. 令top=mid+1,执行步骤2;

代码如下:

int binary_search(int *a, int n, int key)
{
	int top, end, mid;
	top = 0;
	end = n - 1;
	while (top <= end)
	{
		mid = (top + end) / 2;
		if (key < a[mid])
			end = mid - 1;
		else if (key > a[mid])
			top = mid + 1;
		else
			return mid;
	}
	return 0;
}

函数返回所查找值下标。

插值查找

在二分查找中,mid指向中间数,然而在一些情况下这种取法并不好,比如在取值范围0~10000之间100个元素从小到大均匀分布的数组中查找5,如果从中间数开始查找,则中间数必定远远大于5,这样我们会遍历很多不必要的元素,所以我们考虑从下标较小的元素开始查找。
二分查找的mid计算如下:
m i d = t o p + e n d 2 = t o p + 1 2 ( e n d − t o p ) mid=\frac{top+end}{2}=top+\frac{1}{2}(end-top) mid=2top+end=top+21(endtop)
现在我们将公式改进一下:
m i d = t o p + k e y − a [ t o p ] a [ e n d ] − a [ t o p ] ( e n d − t o p ) mid=top+\frac{key-a[top]}{a[end]-a[top]}(end-top) mid=top+a[end]a[top]keya[top](endtop)
改进之后性能有什么改善吗?假设我们查找{1,16,24,35,47,59,62,73,88,99}。如果我们查找16,使用二分查找需要4次,但如果使用插值查找,mid=0+(16-1)/(99-1) × \times ×(9-0)=1.377,取整mid=1,直接便可查找到16这个元素。
插值查找代码如下:

int insert_search(int *a, int n, int key)
{
	int top, end, mid;
	top = 0;
	end = n - 1;
	while (top <= end)
	{
		mid = top + (end - top) * (key - a[top]) / (a[end] - a[top]);
		if (key < a[mid])
			end = mid - 1;
		else if (key > a[mid])
			top = mid + 1;
		else
			return mid;
	}
	return 0;
}

斐波那契查找

很抱歉,斐波那契查找我虽然会但限于领悟程度无法很好的讲解,我找到一个将斐波那契查找很好的文章大家可以参考

斐波那契查找

性能分析

由上述分析可知,二分查找最多只需查找一半的数据,它的时间复杂度为O(logn),好于顺序查找的O(n),但二分查找需要数据有序,对于静态查找而言比较好,但对于需要频繁插入删除操作的数据而言,维护其数据有序需要额外开销得不偿失;插值查找时间复杂度也为O(logn),但对于表较长且关键字分布比较均匀的查找表来说,插值查找比二分查找更好;而斐波那契查找则在海量查找表中发挥优势。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值