说明
二分搜寻法每次搜寻时,都会将搜寻区间分为一半,所以其搜寻时间为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的话,则由索引F5(F5表示第五个费式数作为索引,也就是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代码
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