1.原理介绍
斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为F[n](如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。数组a的长度其实很好估算,比如你定义了有10个元素的有序数组a[20],n=10,那么n就位于8和13,即F[6]和F[7]之间,所以k=7,此时数组a的元素个数要被扩充,为:F[7]-1=12个;再如你定义了一个b[20],且b有12个元素,即n=12,那么很好办了,n = F[7]-1 = 12,用不着扩充了;又或者n=8或9或11,则它一定会被扩充到12;再如n=13,最后得出n位于13和21,即F[7]和F[8]之间,此时k=8,那么F[8]-1=20,数组a就要有20个元素了。所以,n=x(13<=x<=20)时,最后都要被扩充到20;类推,如果n=25呢,则数组a的元素个数肯定要被扩充到 34-1=33个(25位于21和34,即F[8]和F[9]之间,此时k=9,F[9]-1 = 33),所以,n=x(21<=x<=33)时,最后都要被扩充到33。也就是说,最后数组的元素个数一定是(某个斐波那契数-1),这就是一开始说的n与F[k]-1的关系。分割是从mid=low+F[k-1]-1开始的;通过上面知道了,数组a现在的元素个数为F[k]-1个,即数组长为F[k]-1,mid把数组分成了左右两部分,左边的长度为:F[k-1]–1,那么右边的长度就为(数组长-左边的长度-1), 即:(F[k]-1)-(F[k-1]-1)= F[k]-F[k-1]-1=F[k-2]-1。如果一个有序表的元素个数为n,并且n正好是(某个斐波那契数-1),即n=F[k]-1时,才能用斐波那契查找法。如果有序表的元素个n不等于(某个斐波那契数-1),即n≠F[k]-1,这时必须要将有序表的元素扩展到大于n的那个斐波那契数-1才行。时间复杂度:O(logn)。
2.C++代码实现
void fibonacci(int *f) //使用递推关系生成斐波那契数列
{
int i;
f[0] = 1;
f[1] = 1;
for(i=2; i < MAXSIZE; ++i)
f[i] = f[i-2] + f[i-1];
}/*f[i] 1 1 2 3 5 8 13 21 34 55 89
i 0 1 2 3 4 5 6 7 8 9 10
*a是待查找数组的头指针,key待查找的数字,n是待查找数组中元素的个数a[i] 1, 5, 15, 22, 25, 31, 39, 42, 47, 49, 59, 68, 88若 key=39 n=13*/
int fibonacci_search(int *a,int key,int n)
{
int low = 0;
int high = n - 1;//high=13-1 下标从0开始
int mid = 0;
int k = 0;
int F[MAXSIZE];
int i;
fibonacci(F);
//计算n位于斐波那契数列的位置
while( n > F[k]-1 )
++k;
//如果数组的长度小于对应的斐波那契数列中元素的值,那么将他用最大值拓展
// 补充的元素值为最后一个元素的值
//将a的元素扩展到(某斐波那契数 - 1),即F[k]-1
for( i=n; i < F[k]-1; ++i)
a[i] = a[high];
while( low <= high )
{ // low:起始位置0;前半部分有f[k-1]个元素,由于下标从0开始则-1 获取 黄金分割位置元素的下标
mid = low + F[k-1] - 1;//计算当前分割的下标
if( a[mid] > key )//a[5]=31
{ // 查找前半部分,高位指针移动
high = mid - 1;
// (全部元素) = (前半部分)+(后半部分)
// f[k] = f[k-1] + f[k-2]因为前半部分有f[k-1]个元素,所以 k=k-1
k = k - 1;
}
else if( a[mid] < key )//a[5]=31<39
{
// 查找后半部分,高位指针移动
low = mid + 1;
// (全部元素) = (前半部分)+(后半部分)
// f[k] = f[k-1] + f[k-2]因为后半部分有f[k-2]个元素,所以k=k-2
k = k - 2;
}
else
{
if( mid <= high ) //若相等说明mid即为查找到的位置
return mid;
else//若mid>n则说明是扩展的数值,返回n
return high;
}
}
return -1;
}