第二十四章 Caché 算法与数据结构 斐波那契查找

文章目录

第二十四章 Caché 算法与数据结构 斐波那契查找

基本思路

  1. 黄金分割点:是指把一条线段分成两部分,使其中一部分与全长之比等于另一部分与这部分之比,其比值保留三位小数约为0.618。由于按此比例设计的造型十分美丽,因此成为黄金分割,也称为中外比。
  2. 斐波那契数列:{1,1,2,3,5,8,13,21,34,55…}即相邻两个数的和等于这两个数后面的数,通过计算我们可以发现,斐波那契数列中的两个相邻数的比例,无限接近黄金分割值0.618。

注意: 斐波那契查找和前面的两个查找方式类似,也要求待查找的序列是有序的。

  1. 斐波那契查找与二分查找和插值插值相似,只不过改变了划分的节点,不再是中点和插值点,而是位于黄金分割点附近,所以我们需要利用斐波那契数列的特性来找到这个黄金分割点。

步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0uKRXis-1593390544886)(CB898766490D4DBAB34F0C1CA5AAD0E7)]

  1. 由斐波那契数F [ k ]= F [ k - 1] + F[ k - 2 ]的性质,可以得到( F [k] - 1 ) = ( F [ k - 1] - 1 ) + ( F [ k - 2 ] - 1 ) + 1 。该式说明只要顺序表的长度为F[ k ]- 1 ,则可以将该表分成长度为 F[k - 1 ]- 1 和 F [ k - 2] - 1 的两段,即如图所示。从位置为 mid = low + F ( k - 1 )- 1)
  2. 类似的,每一子段也可以用相同的方式分割。
  3. 但顺序表长度 n 不一定刚好等于 F[k]- 1 ,所以需要将原来的顺序表长度 n 增加至 F[k]- 1 。这里的 k 值只要能使得 F[k]-1恰好少于或等于 n 即可,由以下代码得到,顺序表长度增加后,新增的位置(从 n + 1到 F[k]- 1 位置),都赋值为 n 位置的值即可。
    while ( n > f[k]-1)
    k++;

简单来说: 就是根据待排序列的个数,利用斐波那契数列找到一个大于等于序列个数的数,那么这个数前面两个数之比就是分割比例。

复杂度

斐波那契查找可以使用递归实现,也可以使用循环实现。

  • 时间: 当用递归实现时,根据递归树的高度,可得时间复杂度O(2n2^n2
    n
    ),当用循环实现时,时间复杂度位O(n)
  • 空间: 当用递归实现时,空间复杂度O(n),当用循环实现时,空间复杂度位O(n)
算法平均时间最好情形最差情形空间复杂度备注
斐波那契查找O(n)O(n)O(n^2)O(n)待查表是有序表

完整代码示例

斐波那契类

Class PHA.YX.Arithmetic.FibonacciSearch Extends %RegisteredObject
{

/**
   * @description: 创建最大值刚好>=待查找数组长度的裴波纳契数组
   * @param array: 待查找的数组
   */
Method makeFiboArray(array As PHA.YX.Arithmetic.Array) As PHA.YX.Arithmetic.Array
{
	#dim N as %Integer = array.length()
	#dim first as %Integer = 1
	#dim sec as %Integer = 1
	#dim third as %Integer = 2
	#dim fbLength as %Integer = 2
	#dim high as %Integer = array.get(N - 1)
	
	/* 使得裴波那契数不断递增,直到值刚好大于等于原数组长度为止 */
	while (third < N){
		
		/* 根据f(n) = f(n-1)+ f(n-2)计算 */
		s third = first + sec
		s first = sec
		s sec = third
		
		/* 计算最后得到的裴波那契数组的长度 */
		s fbLength = fbLength + 1
	}
	
	/* 根据上面计算的长度创建一个空数组 */
	#dim fb as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d fb.init(fbLength)
	
	/* 第一和一二个数是迭代计算裴波那契数的基础 */
	d fb.set(0, 1)
	d fb.set(1, 1)
	for i = 2 : 1 : fbLength -1 {
		
		/* 将计算出的裴波那契数依次放入上面的空数组中 */
		d fb.set(i, (fb.get(i - 1) + fb.get(i - 2)))
	}
	q fb
}

/**
   * @description: 裴波那契查找
   */
Method search(array As PHA.YX.Arithmetic.Array, key As %Integer)
{
	#dim low as %Integer
	#dim high as %Integer
	#dim lastA as %Integer
	
	/* 创建最大值刚好>=待查找数组长度的裴波纳契数组 */
	#dim fiboArray as PHA.YX.Arithmetic.Array = ..makeFiboArray(array)
	#dim filledLength as %Integer = fiboArray.get(fiboArray.length() - 1)
	
	/* 创建长度等于裴波那契数组最大值的填充数组 */
	#dim filledArray as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d filledArray.init(filledLength)
	
	/* 将原待排序数组的元素都放入填充数组中 */
	for i = 0 : 1 : array.length() - 1 {
		d filledArray.set(i, array.get(i))
	}
	
	/* 原待排序数组的最后一个值 */
	s lastA = array.get(array.length() - 1)
	for i = array.length() : 1 : filledLength - 1 {
		
		/* 如果填充数组还有空的元素,用原数组最后一个元素值填满 */
		d filledArray.set(i, lastA)
	}
	s low = 0
	
	/* 取得原待排序数组的长度 (注意是原数组!) */
	s high = array.length()
	#dim mid as %Integer
	#dim k as %Integer = fiboArray.length() - 1
	while (low <= high){
		s mid =low + fiboArray.get(k - 1) - 1
		if (key < filledArray.get(mid)){
			
			/* 排除右半边的元素 */
			s high = mid - 1
			
			/* f(k-1)是左半边的长度 */
			s k = k - 1
		}elseif(key > filledArray.get(mid)){
			
			/* 排除左半边的元素 */
			s low = mid + 1
			
			/* f(k-2)是右半边的长度 */
			s k = k - 2
		}else{
			
			/* 说明取到了填充数组末尾的重复元素了 */
			if (mid > high){
				return high
			}else{
				
				/* 说明没有取到填充数组末尾的重复元素 */
				return mid
			}
		}
	}
	return -1
}

}

调用


/// w ##class(PHA.YX.Arithmetic).FibonacciSearch(77)
ClassMethod FibonacciSearch(x)
{
	#dim array as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d array.init(10)
	d array.insert(0,11)
	d array.insert(1,22)
	d array.insert(2,33)
	d array.insert(3,44)
	d array.insert(4,55)
	d array.insert(5,66)
	d array.insert(6,77)
	d array.insert(7,88)
	d array.insert(8,99)
	d array.insert(9,111)
	#dim search as PHA.YX.Arithmetic.FibonacciSearch = ##class(PHA.YX.Arithmetic.FibonacciSearch).%New() 
	s index = search.search(array, x)
	w "------斐波那契数列-----",!
	w index,!
	
	q ""
}
DHC-APP>w ##class(PHA.YX.Arithmetic).FibonacciSearch(77)
------斐波那契数列-----
6
 
DHC-APP>w ##class(PHA.YX.Arithmetic).FibonacciSearch(11)
------斐波那契数列-----
0
 
DHC-APP>w ##class(PHA.YX.Arithmetic).FibonacciSearch(2)
------斐波那契数列-----
-1
 
DHC-APP>w ##class(PHA.YX.Arithmetic).FibonacciSearch(22)
------斐波那契数列-----
1
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yaoxin521123

谢谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值