#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(" "); 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 ",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]) */