斐波那契查找(FibonacciSearch)

说明
二分搜寻法每次搜寻时,都会将搜寻区间分为一半,所以其搜寻时间为O(log(2)n),log(2)表示以2为底的log值,这边要介绍的费氏搜寻,其利用费氏数列作为间隔来搜寻下一个数,所以区间收敛的速度更快,搜寻时间为O(logn)。

方法
该方法稍有些繁琐,对照代码更容易理解。费氏搜寻使用费氏数列来决定下一个数的搜寻位置,所以必须先制作费氏数列,这在之前有提过;费氏搜寻会先透过公式计算求出第一个要搜寻数的位置,以及其代表的费氏数,以搜寻对象10个数字来说,第一个费氏数经计算后一定是F5,而第一个要搜寻的位置有两个可能,例如若在下面的数列搜寻的话(为了计算方便,通常会将索引0订作无限小的数,而数列由索引1开始):

-∞ 1 3 5 7 9 13 15 17 19 20

如果要搜寻5的话,则由索引F5F5表示第五个费式数作为索引,也就是5)开始搜寻,接下来如果数列中的数大于指定搜寻值时,就往左找,小于时就向右,每次找的间隔是F4(第四个费式数作为索引,也就是3)、F3(第三个费式数作为索引,也就是2)、F2(第二个费式数作为索引,也就是1)来寻找,当费氏数为0时还没找到,就表示寻找失败,如下所示:

如果要搜寻19,由于第一个搜寻值索引F5处的值小于19,所以此时必须对齐数列右方,也就是将第一个搜寻值的索引改为F5+2 = 7,然后如同上述的方式进行搜寻,如下所示:

至于第一个搜寻值是如何找到的?我们可以由以下这个公式来求得,其中n为搜寻对象的个数,Fy为第y个费式数,必须大于等于n,若算出x值,则使用Fx作为第一个搜寻索引,也就是第x个费式数:

以10个搜寻对象来说:

Fy = 8, m = 2,所以可以对照费氏数列得到8是第六个费式数,所以y=6,所以x得5,也就是使用第五个费式数的值(也就是5)作为索引开始搜寻。

如果数列在索引5处的值大于指定的搜寻值,则第一个搜寻位置就是索引5的位置,如果小于指定的搜寻值,则第一个搜寻位置必须加上m,也就是F5 + m = 5 + 2 = 7,也就是索引7的位置,其实加上m的原因,是为了要让下一个搜寻值刚好是数列的最后一个位置。

费氏搜寻看来难懂,但只要掌握Fy + m = n这个公式,自己找几个实例算一次,很容易就可以理解;费氏搜寻除了收敛快速之外,由于其本身只会使用到加法与减法,在运算上也可以加快。


C代码

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#define INT_MIN -9999

void createFibonacci(int[], int);    
int findY(int[], int);         
int fibonacciSearch(int[], int, int);  

int main(void) {    
	int number[] = {1, 2, 3, 5, 6, 8, 9, 10, 11};
	int length = sizeof(number) / sizeof(int);

	printf("数列:"); 
	int i;
	for(i = 0; i < length; i++) 
		printf("%d ", number[i]); 

	printf("\n输入寻找对象:"); 
	int find;
	scanf("%d", &find); 

	if((i = fibonacciSearch(number, length, find)) >= 0) 
		printf("找到数字于索引:%d ", i); 
	else 
		printf("\n找不到指定数"); 

	printf("\n"); 

	return 0; 
} 

//建立斐波那契数列
void createFibonacci(int Fib[], int length) { 
	Fib[0] = 0; 
	Fib[1] = 1; 
	int i;
	for(i = 2; i < length; i++) 
		Fib[i] = Fib[i-1] + Fib[i-2]; 
} 

//找Y值 
int findY(int Fib[], int n) { 
	int i = 0; 
	while(Fib[i] <= n) i++; 
	i--; 
	return i; 
} 

//斐波那契查找
int fibonacciSearch(int number[], int length, int find) { 
	int* Fib = (int*)(malloc(length * sizeof(int)));
	int f;
	for(f = 0; f < length; f++) {
		Fib[f] = INT_MIN;
	}

	createFibonacci(Fib, length); 

	int y  = findY(Fib, length + 1); 
	int m = length - Fib[y]; 
	int x = y - 1; 
	
	int i = x; 
	if(number[i] < find) 
		i += m; 

	int result = -1;
	while(Fib[x] > 0) { 
		if(number[i] < find) 
			i += Fib[--x]; 
		else if(number[i] > find) 
			i -= Fib[--x]; 
		else {
			result = i;
			break;
		}
	} 

	free(Fib);

	return result; 
}  

转载自: http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/FibonacciSearch.htm



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值