简介
斐波那契搜索(Fibonacci search) ,又称斐波那契查找,是区间中单峰函数的搜索技术。
斐波那契搜索就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为Fn,完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
斐波那契数列
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
原理
-
斐波那契查找原理与二分查找相似,只是改变的mid的位置,位于黄金分割点附近,即 mid = low + f[k - 1] - 1;
-
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,就可以把该表分为f[k-1] - 1和f[k-2] - 1的两部分,中间位置为mid = low + f[k - 1] - 1; -
顺序表长度n不一定刚好等于f[k] - 1,需要将顺序表长度n增加到f[k] - 1,f[k] - 1刚好大于或等于n即可,新增的位置都赋值为n位置的值。
while (height > f[k] - 1) {
k++;
}
代码
/**
* 因为斐波那契查找算法需要用到斐波那契数列,mid=low+F(k-1)-1
* @return 返回一个斐波那契数列
*/
public static int[] fib() {
int[] fib = new int[MAX_SIZE];
fib[0] = 1;
fib[1] = 1;
for (int i = 2; i < MAX_SIZE; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
return fib;
}
/**
* @param arr 数组
* @param value 查找的值
* @return 找到就返回值的下标,没找到返回-1
*/
public static int fibonacciSearch(int[] arr,int value) {
int low = 0;
int height = arr.length - 1;
//斐波那契分割数值的下标
int k = 0;
int mid;
//斐波那契数列
int[] f = fib();
//获取斐波那契分割数值的下标
while (height > f[k] - 1) {
k++;
}
//因为f[k]的值可能大于数组的长度,所以使用Arrays构建一个新的数组,不足的部分使用0补充
int[] temp = Arrays.copyOf(arr,f[k] - 1);
//使用arr数组最后的值补充后面的部分 [1,2,3,4,5,6,0,0] ==>[1,2,3,4,5,6,6,6]
for (int i = height + 1; i < temp.length; i++) {
temp[i] = arr[height];
}
while (low <= height) {
mid = low + f[k - 1] - 1;
if (temp[mid] > value) {
//向mid的左边找
height = mid - 1;
//f[k] = f[k-1] + f[k-2] mid就是f[k]的黄金分割点附近,即f[k-1]和f[k-2]的中间,
//mid比要查找的值value大,就向左边查找,f[k-1]为f[k]
k--;
} else if (temp[mid] < value) {
//向mid的右边找
low = mid + 1;
//f[k] = f[k-1] + f[k-2] mid就是f[k]的黄金分割点附近,即f[k-1]和f[k-2]的中间,
//mid比要查找的值value小,就向右边查找,f[k-2]为f[k]
k -= 2;
} else {
//找到了,需要确定,返回的是哪个下标
return Math.min(mid,height);
}
}
//没有找到
return -1;
}
测试
int[] arr = {1,2,3,4,5,6};
int result = fibonacciSearch(arr,3);
System.out.println("result = " + result);