目录
一:斐波那契思想
斐波那契查找思路
说句实在话,这个斐波那契查找我看了不下5遍才理解他的思路和代码,因为它里面的值太多,不好理解容易绕晕,所以我给大家用自己的理解讲一下
什么是斐波那契:
要想学会斐波那契查找,首先你得知道什么是斐波那契数列
斐波那契数列,又称黄金分割数列,指的是这样一个数列: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]个元素,找出要查找的元素在那一部分并递归,直到找到。
值得一提的是当有序表的元素个数不是斐波那契数列中的某个数字时,需要把有序表的元素个数长度补齐,让它成为斐波那契数列中的一个数值,补上的数值是原数组的最后一个元素,当然把原有序表截断肯定是不可能的,不然还怎么查找。然后图中标识每次取斐波那契数列中的某个值时(F[k]),都会进行-1操作,这是因为有序表数组位序从0开始的,纯粹是为了迎合位序从0开始
如果这样你还是不明白,我只能举例给你来说明
比如有一个数组arr={1,2,3,4,5,6,7,8,9,10,11,12}要对他进行斐波那契查找,查找的值是10
首先,你得创建一个斐波那契数列出来我们定义为f[k],长度暂且定义为10吧那f={1,1,2,3,5,8,13,21,34,55},创建好了之后,我们再看原数组长度arr.length=12,根据斐波那契查找原则我们发现他的长度不等于斐波那契数列的某一个数值,所以我们要将数组的长度补至最近的斐波那契数,好,我们最近的值是13,所以我们复制最后一个元素至arr数组末尾(当然,数组长度是不能改变的,我们只能创建一个新的数组来复制arr数组的值并复制最后一个元素添加到末尾),好,新的数组元素就是{1,2,3,4,5,6,7,8,9,10,11,12,12}
接下来得找查找算法里的中间值了,斐波那契查找发就是将原序列分为斐波那契数组里的连续的两个值,上面我们说了原序列长度为13,在斐波那契数列里找到f[k]=f[k-1]+f[k-2],即13=8+5,f[6]=f[5]+f[4],则中间值就是f[5]=8
找到中间值之后下来就是递归了,将目标值和中间值进行比较,如果目标值小于中间值,说明向左递归,将左边的部分继续分解为两个斐波那契数,以此类推直到找到目标数
二:斐波那契代码
package look;
import java.util.Arrays;
public class NewFibonaciLook {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,8,10,18,20};
System.out.print(FibonaciSearch(arr, 28));
}
public static int[] f() {
int[] f = new int[20];
f[0] = 1;
f[1] = 1;
for(int i = 2; i < f.length; i++) {
f[i] = f[i -1] + f[i - 2];
}
return f;
}
public static int FibonaciSearch(int[] arr, int key) {
int low = 0;
int high = arr.length - 1;
int mid = 0;
int k = 0;
int[] f = f();
while(high > f[k] - 1) {
k++;
}
int[] temp = Arrays.copyOf(arr, f[k]);
for(int i = high + 1; i < temp.length; i++) {
temp[i] = arr[high];
}
while(low <= high) {
mid = low + f[k - 1] - 1;
if(temp[mid] > key) {
high = mid - 1;
k--;
}else if(temp[mid] < key) {
low = mid + 1;
k -= 2;
}else {
if(mid <= high) {
return mid;
}else {
return high;
}
}
}
return -1;
}
}