#include<stdio.h>
#include<string.h>
#include<iostream>
#include<iostream>
#include<cmath>
using namespace std;
int f[1005];
void init()
{
int i,j;
f[0]=0;
f[1]=1;
for(i=2; i<1000; i++)
f[i]=f[i-1]+f[i-2];
//以上进行斐波那契数组初始化
}
int Fibonacci_Search(int *a,int n,int key)
{
init();
int low=0,high=n-1,mid,k=0;//注意下标
int i,j;
while(n>f[k]-1)k++;//这里执行完之后m,f[k]-1>n
for(i=n; i<f[k]-1; i++)
a[i]=a[n-1];//扩展到f[k]-1;
/*
为什么需要把数组长度扩充到f[k]-1而不是f[k]或者f[k+1]?这是为了能正确递归计算mid值,
看下图可发现 f[k]-1 = (f[k-1] + f[k-2]) - 1 = (f[k-1]-1) + 1 + (f[k-2]-1),
中间的1就是我们二分的锚点mid,如果目标在左区,数组长度就缩到(f[k-1]-1),如果在右区,
数组长度就缩到(f[k-2]-1),否则就等于mid完成查找。而(f[k-1]-1)又能拆成(f[k-2]-1)+1+(f[k-3]-1),
这样递归分割下去就能不断的缩小区间直至找到目标。
也也就是说:如果一个有序表的元素个数为n,并且n正好是(某个斐波那契数 - 1),即n=F[k]-1时,才能用斐波那契查找法。
如果有序表的元素个n不等于(某个斐波那契数 - 1),即n≠F[k]-1,这时必须要将有序表的元素扩展到大于n的那个斐波那契数 - 1
*/
// for(i=0;i<f[k]-1;i++)
// printf("%d ",a[i]);
//printf("\n");
while(low<=high)
{
mid=low+f[k-1]-1;
//low就是此时的左边下标,也就是黄金分割的起始点,f[k-1]-1代表个数,并不是所谓的数组下标从0开始
//这里可以对比二分查找理解,其实low high下标变化完全一样,不一样的就是mid值的变化,斐波那契是采用黄金分割
//而二分查找是采用对半分割
if(a[mid]>key)
{
high=mid-1;
k=k-1;
}
else if(a[mid]<key)
{
low=mid+1;
k=k-2;
}
else
{
if(mid<=n)return mid;
else return n;
}
}
return -1;
}
int main()
{
int i,j,k,n;
int a[10000];
while(scanf("%d%d",&n,&k)!=EOF)
{
for(i=0; i<n; i++)scanf("%d",&a[i]);
printf("%d\n",Fibonacci_Search(a,11,k));
}
return 0;
}
/*
11 0
0 1 16 24 35 47 59 62 73 88 99
11 88
0 1 16 24 35 47 59 62 73 88 99
11 1
0 1 16 24 35 47 59 62 73 88 99
*/
/*
斐波那契查找的核心是:
1)当key=a[mid]时,查找成功;
2)当key<a[mid]时,新的查找范围是第low个到第mid-1个,此时范围个数为F[k-1] - 1个,即数组左边的长度,所以要在[low, low+F[k - 1] - 1]范围内查找;
3)当key>a[mid]时,新的查找范围是第mid+1个到第high个,此时范围个数为F[k-2] - 1个,即数组右边的长度,所以要在[(mid+1),(mid+1)+F[k - 2] - 1]范围内查找。
联系黄金分割比例来分析,黄金分割分成两部分,一段长(即是发f[k-1]),一段短(f[k-2])
*/