参考博客:
1.斐波那契查找原理详解与实现
2.斐波那契查找(黄金分割法查找)(仅使用加减实现的二分查找)
斐波拉契数列
斐波那契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、••••,在数学上,斐波那契被递归方法如下定义:F(1)=1,F(2)=1,F(n)=f(n-1)+F(n-2) (n>=2)。该数列越往后相邻的两个数的比值越趋向于黄金比例值(0.618)。
基本思想
斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为Fn,完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
程序示例
//a为要查找的数组,n为要查找的数组长度,key为要查找的关键字
int Fibonacci_Search(int *a, int n, int key)
{
int low = 0, k = 0;
int high = n - 1;
int F[max_size];
Fibonacci(F); //构造一个斐波那契数组F
while(n > F[k]-1) //计算n位于斐波那契数列的位置
++k;
int* temp = new int[F[k]-1]; //将数组a扩展到F[k]-1的长度
memcpy(temp, a, n*sizeof(int));
for(int i = n; i < F[k]-1; ++i)
temp[i] = a[n-1];
while(low <= high)
{
int mid = low + F[k-1] - 1;
if(key < temp[mid])
{
high = mid - 1;
k -= 1;
}
else if(key > temp[mid])
{
low = mid + 1;
k -= 2;
}
else
{
if(mid < n) return mid; //若相等则说明mid即为查找到的位置
else return n-1; //若mid>=n则说明是扩展的数值,返回n-1
}
}
delete[] temp;
return -1;
}
首先初始化一个拥有max_size大小的斐波拉契数组F,然后寻找一个略大于数组a长度的斐波拉契数F[k],即n <= F[k]-1,n < F[k]。而后申请了一个F[k]-1大小的数组temp,并初始化。
我们从上一段话中看到,程序中反复地提到一个尺寸量F[k]-1。现就此提出两个问题: ①. 为什么要查找这样一个k,使得n <= F[k]-1,而非n <= F[k]?
②. 为什么另申请的数组temp的长度为F[k]-1,而非F[k]?
这样做的目的就是为了钳位这样一个k,使得数组的长度等于F[k]-1,而F[k]-1 = F[k-1]-1 + mid位 + F[k-2]-1。例如,k=5的时候,F[k]-1 = 4,F[k-1]-1 = 2,,F[k-2]-1 = 1,即满足4 = 2 + mid位 + 1。这样就总能找到一个mid使得其前半部分序列和后半部分序列满足:
F[x]-1 (x可以为1,2,3...)
这样处理之后(即减1操作)就总能满足递归的条件。
下面继续程序的讲解。temp初始化之后,进入循环体。在循环体内,先对mid位上的值与key值进行比较,若key < temp[mid],则将F[k]-1长数组的前半部分F[k-1]-1作为新的递归序列,若key > temp[mid],就使用后半部分F[k-2]-1,如此就实现了二分。