查找算法:斐波那契查找

Searching Algorithms: Fibonacci Search

. 前言

该博客用于本弱鸡复习巩固,打牢基础,还望各大佬不吝赐教。java

. 基本思路

  1. 获取待查数组 a 的长度 n ,经过查找斐波那契序列,找序列中出大于n的最小值 fibo 所在的角标 index ,或者等于n的值的所在角标。
  2. 根据获取的 fibo 的值减一加长待查数组(另new一个新数组temp),补充的值为待查数组的最大值。
  3. 开始查找:计算出 mid ,查找 temp[mid] , 与key做比较,直到找到key所在的位置。
  • 该算法的核心在于如何计算mid,也就是如何分割数组来进行查找。
  • 设斐波那契数列为 F[index]
    令 mid = low + F[index - 1] -1
    若 key == temp[mid] ,查找成功
    若 key < temp[mid],新的范围是第 low 到第 mid-1,此时该范围个数为 F[index-1]-1 个 若 key > temp[mid],新的范围就是第 mid+1 到第 high 个,此时该范围个数为 F[index-2]-1个
  • 对于斐波那契数列 F[index]-1 = F[index-1] + F[index-2] -1
    index >= 2

. 图片示例

mid 将 temp 数组一分为2
mid 将 temp 数组一分为2

. 算法复杂度分析

  • 算法复杂度 O(logn)
  • 平均性能要因为折半查找,若是是最坏状况好比如本例程序中 key=1,那么始终在左侧长半区查找,则查找效率要低于折半查找。
  • 二分查找分割方式 mid = (low+high)/2 加法和除法
  • 插值查找分割方式 mid = low + (high-low)*(key-a[low])/(a[high]-a[low]) 加减乘除都用上了
  • 斐波那契查找分割方式 mid = low + Fibonacci[index - 1] - 1
  • 海量数据查找中,这种细微的差距会影响最终的查找效率。

. 代码实现

 1import java.util.ArrayList;
2import java.util.Arrays;
3
4/**
5 * Fibonacci Search 斐波那契查找,利用黄金分割原理实现
6 * 
7 * 算法复杂度 O(logn)
8 * 
9 * 二分查找分割方式 mid = (low+high)/2  加法和除法
10 * 插值查找分割方式 mid = low + (high-low)*(key-a[low])/(a[high]-a[low]) 加减乘除都用上了
11 * 斐波那契查找分割方式 mid = low + Fibonacci[index - 1] - 1
12 * 
13 * Fibonacci Search examines relatively closer elements in subsequent steps.
14 * So when input array is big that cannot fit in CPU cache or even in RAM, Fibonacci Search can be useful.
15 */

16public class FibonacciSearch {
17
18    public static void main(String[] args) {
19        int[] a = new int[]{1162435475962738899};
20        System.out.println("待查找数组 a:");
21        System.out.println(Arrays.toString(a));
22        System.out.println();
23        //查找示例1
24        int key = 1;
25        System.out.println("寻找的key为:" + key);
26        System.out.println("结果在数组 a 角标的 [" + fibonacciSearch(key, a) + "] 位");
27        System.out.println();
28        //查找示例2
29        int key1 = 99;
30        System.out.println("寻找的key为:" + key1);
31        System.out.println("结果在数组 a 角标的 [" + fibonacciSearch(key1, a) + "] 位");
32    }
33
34    public static int fibonacciSearch(int key, int[] a) {
35        //初始化记录首位 末位 mid非字面意义上的中间值,仅是将数组分割为两部分
36        int low = 0;
37        int high = a.length - 1;
38        int mid;
39        //斐波那契数列中的值-1
40        int fibo = 0;
41        //斐波那契数列中的角标值
42        int index = 0;
43        //用于展现斐波那契数列
44        ArrayList<Integer> fiboArr = new ArrayList<Integer>();
45        //计算length位于斐波那契数列的位置
46        while (a.length > fibo) {
47            fibo = getFibonacci(index) - 1;
48            fiboArr.add(fibo + 1);
49            index++;
50        }
51        //用于展现
52        System.out.println("待查找数组长度为:" + a.length);
53        System.out.println("斐波那契数列为:");
54        System.out.println(fiboArr.toString());
55        System.out.println("斐波那契角标 [" + (index - 2) + "] 位为:" + getFibonacci(index - 2));
56        System.out.println("斐波那契角标 [" + (index - 1) + "] 位为:" + getFibonacci(index - 1));
57        System.out.println();
58        //-----------------------------
59
60        //要找到在斐波那契数列中大于待查数组长度值的最小值的角标,或者等于待查数组长度值的角标
61        index -= 1;
62        //定义临时数组来扩展待查数组的长度,长度为 fibo
63        int[] temp = new int[fibo];
64        for (int i = a.length; i < temp.length; i++) {
65            temp[i] = a[a.length - 1];
66        }
67        for (int i = 0; i < a.length; i++) {
68            temp[i] = a[i];
69        }
70        //展现
71        System.out.println("补充后的数组 temp 为:");
72        System.out.println(Arrays.toString(temp));
73        System.out.println("补充后的数组长度为:" + temp.length);
74        //----------------
75
76        //开始查找
77        while (low <= high) {
78            //计算分割数组处的角标
79            mid = low + getFibonacci(index - 1) - 1;
80
81            System.out.println("斐波那契角标 =  " + index + "   将key与数组的角标 [" + (mid) + "] 所在的值作比较");
82
83            if (key < temp[mid]) {
84                high = mid - 1;
85                index -= 1;
86            } else if (key > temp[mid]) {
87                low = mid + 1;
88                index -= 2;
89            } else {
90                //若是值相等且角标小于或等于待查数组的最大角标 返回mid 表示找到
91                if (mid <= a.length - 1) {
92                    return mid;
93                } else {
94                    //若是值相等但角标大于待查数组的最大角标
95                    //这样表示在与temp数组比较时,比较的角标超过了待查数组的角标
96                    //但在补充temp数组时,后面的值都是待查数组的最后一位值
97                    //因此所寻找的key正好是待查找数组的最后一位
98                    System.out.println("所寻找的key正好是待查找数组的最后一位");
99                    return a.length - 1;
100                }
101            }
102        }
103        return 0;
104    }
105
106    //生成斐波那契数列
107    public static int getFibonacci(int k) {
108        if (k == 0) {
109            return 0;
110        } else if (k == 1) {
111            return 1;
112        } else if (k > 1) {
113            return getFibonacci(k - 1) + getFibonacci(k - 2);
114        } else {
115            return -1;
116        }
117    }
118}
复制代码

. 程序运行截图

程序运行截图
程序运行截图

. 参考

相关文章
相关标签/搜索