目录
斐波那契查找的基本介绍
在中学阶段我们都学过黄金分割比为0.618,在斐波那契数列中,相邻两个数的比例,无限接近0.618
斐波那契(黄金分割法)原理
斐波那契查找与前两种查找方法相似,仅仅是改变了中间节点mid的位置,mid不再是由二分或者差值得到,而是位于黄金分割点附近。即:mid=left+F[k-1]-1,(F表示斐波那契数列),如下图所示:
对于F[k]-1的理解
(1)因为斐波那契数列满足:F[k]=F[k-1]+F[k-2],所以F[k]-1=(F[k-1]-1)+(F[k-2]-1)+1
该式说明:对于长度为F[k]-1的斐波那契数列,我们总能找到一个mid,将其分为长度为F[k-1]-1和F[k-2]-1两个部分。
(2)类似的,对于每一子段,也可以用相同的方法分割。
(3)但是顺序表的长度不一定为F[k]-1,所以我们要对原先的表进行扩容。这里只需要让F[k]-1>=n就可以。新增的位置都赋值为n位置的值
int k = 0;//记录F的下标
//找到满足条件的下标 F[k]-1>n
while (n > F[k] - 1) {
++k;
}
int* tmp = new int[F[k] - 1]; //将数组扩展到F[k]-1的长度
memcpy(tmp, a, n * sizeof(int));
//扩展数组,多出的部分按照最后一个元素处理
for (int i = n; i < F[k] - 1; i++) {
tmp[i] = a[n - 1];
}
斐波那契查找的代码实现
(1)首先我们要得到一个斐波那契数列
#define max_size 20
void Fibonacci(int* F)
{
F[0] = 1;
F[1] = 1;
for (int i = 2; i < max_size - 1; i++) {
F[i] = F[i - 1] + F[i - 2];
}
}
(2)先扩容,然后进行查找
int Fibonacci_Search(int* a, int n, int k) {
int low = 0;
int high = n - 1;
int F[max_size];
Fibonacci(F);
int k = 0;//记录F的下标
//找到满足条件的下标 F[k]-1>n
while (n > F[k] - 1) {
++k;
}
int* tmp = new int[F[k] - 1]; //将数组扩展到F[k]-1的长度
memcpy(tmp, a, n * sizeof(int));
//扩展数组,多出的部分按照最后一个元素处理
for (int i = n; i < F[k] - 1; i++) {
tmp[i] = a[n - 1];
}
while (left <= right) {
int mid = low + F[k - 1] - 1;
if (k < tmp[mid]) {
high = mid - 1;
k-=1;
}
else if (k > tmp[mid]) {
low = mid + 1;
k -= 2;
}
else
{
if (mid < n) {
return mid;//说明mid即为查找到的位置
}
else{
return n - 1;//mid>=n说明是在扩展的地方找到的,返回n-1(最后一位)
}
}
}
return -1;
}
这里需要理解的点
(1)对k的不同处理:
如果当k<a[mid]时,说明新范围是low到第mid-1个,此时范围个数为F[k-1]-1(即原先的左区间)
如果当k>a[mid]时,说明新范围是mid+1到第high个,此时范围个数为F[k-2]-1(即原先的右区间)
所以要对k进行k-=1(下一次在左区间细分)或者k-=2(下一次在右区间细分的处理)