1. 程式人生 > 其它 >斐波那契查詢

斐波那契查詢

簡介
斐波那契搜尋(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*)
原理

  1. 斐波那契查詢原理與二分查詢相似,只是改變的mid的位置,位於黃金分割點附近,即 mid = low + f[k - 1] - 1;

  2. 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;

  3. 順序表長度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);