斐波那契查找
本次内容基于b站尚硅谷韩顺平老师的数据结构与算法
基本介绍
原理
斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为Fn,完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
值得一提的是当有序表的元素个数不是斐波那契数列中的某个数字时,需要把有序表的元素个数长度补齐,让它成为斐波那契数列中的一个数值,补上的数值是原数组的最后一个元素,当然把原有序表截断肯定是不可能的,不然还怎么查找。然后图中标识每次取斐波那契数列中的某个值时(F[k]),都会进行-1操作,这是因为有序表数组位序从0开始的,纯粹是为了迎合位序从0开始.
代码部分
public class FibonacciSearch {
public static int maxSize = 20;
public static void main(String[] args) {
int[] arr = new int[]{1,8,10,89,1000,1024};
System.out.println( fibonacciSearch(arr,89));
}
//因为后面我们mid=low+F(k-1)-1,需要使用到斐波那契数列,因此我们需要先获取到一个斐波那契数列
//非递归方法得到一个斐波那契数列
public static int[] fib(){
int f[] = new int[maxSize];
f[0]=1;
f[1]=1;
for (int i=2;i<maxSize;i++){
f[i] = f[i-1]+f[i-2];
}
return f;
}
/**
* @param arr 数组
* @param key 我们需要查找的关键码(值)
* @return 返回对应的下标,如果没有-1
*/
public static int fibonacciSearch(int[]arr,int key){
int low = 0;
int high = arr.length - 1;
int k = 0; //表示斐波那契分割数值的下标
int mid = 0; //存放mid值
int f[] = fib(); //获取到斐波那契数列
while (high>f[k]-1){ //获取到斐波那契分割数值的下标
k++;
}
//因为 f[k] 值 可能大于 arr 的 长度,因此我们需要使用Arrays类,构造一个新的数组,并指向temp[]
//不足的部分会使用0填充
int temp[] = Arrays.copyOf(arr,f[k]);
for(int i =high;i<temp.length;i++){
temp[i] = arr[high];
}
//实际上需求使用a数组最后的数填充 temp
// 使用while来循环处理,找到我们的数 key
while (low<=high){
mid = low + f[k - 1] - 1;
if (temp[mid]>key) { //如果temp[mid]>key,说明我们应该向左找
high=mid-1;
k--;
//为什么是 k--
//说明
//1. 全部元素 = 前面的元素 + 后边元素
//2. f[k] = f[k-1] + f[k-2]
//因为 前面有 f[k-1]个元素,所以可以继续拆分 f[k-1] = f[k-2] + f[k-3]
//即 在 f[k-1] 的前面继续查找 k--
//即下次循环 mid = f[k-1-1]-1
}else if (temp[mid]<key){
low=mid+1;
k-=2;
//为什么是k -=2
//说明
//1. 全部元素 = 前面的元素 + 后边元素
//2. f[k] = f[k-1] + f[k-2]
//3. 因为后面我们有f[k-2] 所以可以继续拆分 f[k-2] = f[k-3] + f[k-4]
//4. 即在f[k-2] 的前面进行查找 k -=2
//5. 即下次循环 mid = f[k - 1 - 2] - 1
}else { 需要确定,返回的是哪个下标
if(mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1; //循环结束后要是都没返回,说明没找到这个数,那就返回-1
}
}