查找算法:斐波那契查找

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}
複製代碼

. 程序運行截圖

程序運行截圖
程序運行截圖

. 參考

相關文章
相關標籤/搜索