24、查找算法-斐波那契查找
来源:https://www.bilibili.com/video/BV1B4411H76f?p=77
一、思路
斐波那契查找:也可以说是黄金分割法查找,斐波那契序列{1,1,2,3,5,8,13...},相邻两个数的比值无限接近于黄金分割值(0.618)。这里还是对中间下标mid进行修改。
斐波那契满足的性质是这样的: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,剩下那个1就是一个中间值。现在,长度划分好了。有两个问题:原始长度不满足F(k)-1怎么办?mid下标怎么计算?
原始长度可以通过扩充的形式来增长,增长的部分用原始数组的最后一个数填补;
mid=low+F(k-1)-1,即左边是较长的一部分,右边较短。
二、实现
1 //斐波那契查找 2 public class FibonacciSearch { 3 //给定一个斐波那契数组的最大长度 4 public static int MAXSIZE = 20; 5 6 public static void main(String[] args) { 7 int[] arr = {1,8,10,89,1000,1234}; 8 System.out.println(Arrays.toString(arr)); 9 10 int a = fibSearch(arr,89); 11 System.out.println(a); 12 } 13 14 //给定斐波那契的所有情况 15 public static int[] fib(){ 16 int[] f = new int[MAXSIZE]; 17 f[0] = 1; 18 f[1] = 1; 19 for (int i = 2; i < MAXSIZE; i++) { 20 f[i] = f[i-1]+f[i-2]; 21 } 22 return f; 23 } 24 25 public static int fibSearch(int[] arr,int finalVal){ 26 int left = 0; 27 int right = arr.length - 1; 28 //长度补齐 29 int[] fib = fib(); 30 int k = 0;//找长度 31 while(right > fib[k] - 1){ 32 k++; 33 } 34 int[] temp = Arrays.copyOf(arr,fib[k]);//补齐 35 for (int i = right + 1; i < temp.length; i++) { 36 temp[i] = arr[right]; 37 } 38 39 int mid = 0; 40 while (left <= right){ 41 mid = left + fib[k-1] - 1; 42 if(finalVal < temp[mid]){ 43 //向左找 44 right = mid - 1; 45 //按照mid的计算方式,左边是较长的序列,其长度对应的是k-1这个下标的前一个k-1-1 46 k -= 1; 47 }else if (finalVal > temp[mid]){ 48 //向右找 49 left = mid + 1; 50 //按照mid的计算方式,右边是较短的序列,其长度对应的是k-1这个下标的前两个k-1-2 51 k -= 2; 52 }else { 53 //因为之前扩容过,得看找到的这个mid在不在扩容的范围里面(返回的是下标,在扩容的里面就是数组最后一个) 54 if(mid <= right){ 55 //不属于扩容的范围 56 return mid; 57 }else { 58 return right; 59 } 60 } 61 } 62 return -1; 63 } 64 }
这里用递归好像反而不好整了,需要单独将补齐的工作分开,输入进去的应该是补齐后的数组。输出的时候也要单独判断在不在扩充区。