斐波那契查找法原理解析

  1. #include <iostream>
  2. #include <assert.h>

  3. #define MAXSIZE 13

  4. void Fibonacci(int *f)
  5. {
  6.     f[0] = 1;
  7.     f[1] = 1;

  8.     for (int i = 2; i < MAXSIZE; i++)
  9.     {
  10.         f[i] = f[i - 1] + f[i - 2];
  11.     }
  12. }

  13. int Fibonacci_Search(int *a, int n, int key)
  14. {
  15.     int low, high, mid;

  16.     low = 1;
  17.     high = n - 1;
  18.  
  19.     int k = 0;
  20.     int F[MAXSIZE];
  21.     Fibonacci(F);

  22.      //這個查找n在斐波那契數列中的位置,爲什麼是F[k] - 1,而不是F[k]
  23.     while ( n > F[k] - 1 )
  24.     {
  25.         k++;
  26.     }

  27.     //這個地方,我發現被查找的數組a的長度不好計算,比如,我現在要查找31在數組a中的位置
  28.     //那麼,由於n = 13, 位於斐波那契數列中的第7個數(21)和第8個數(34)之間,所以k的
  29.     //值爲7,F[k] - 1就等於20,那麼數組a的長度就需要是a[20]。換個數又變了,我不知道這個
  30.     //應該怎麼控制?
  31.     for (int i = n; i < F[k] - 1; i++)
  32.     {
  33.         a[i] = a[high];
  34.     }

  35.         //還有這個判斷,當鍵值小於a[mid]時,就在[low, F[k - 1] - 1]範圍內查找
  36.         //當鍵值大於a[mid]時,就在[F[k - 2] - 1]範圍內查找,這個依據是什麼?
  37.     while(low <= high)
  38.     {
  39.         mid = low + F[k - 1] - 1;

  40.         if ( key < a[mid] )
  41.         {
  42.             high = mid - 1;
  43.             k = k - 1;
  44.         }
  45.         else if ( key > a[mid] )
  46.         {
  47.             low = mid + 1;
  48.             k = k - 2;
  49.         }
  50.         else
  51.         {
  52.             if ( mid <= high )
  53.             {
  54.                 return mid;
  55.             }
  56.             else
  57.                 return n;
  58.         }
  59.     }
  60.     return -1;
  61. }

解析:
首先要明確:如果一個有序表的元素個數爲n,並且n正好是(某個斐波那契數 - 1),即n=F[k]-1時,才能用斐波那契查找法。 如果有序表的元素個n不等於(某個斐波那契數 - 1),即n≠F[k]-1,這時必須要將有序表的元素擴展到大於n的那個斐波那契數 - 1才行,這段代碼:
for (int i = n; i < F[k] - 1; i++)
  {
  a[i] = a[high];
  }
便是這個作用。

下面回答
第一個問題:看完上面所述應該知道①是爲什麼了吧。 查找n在斐波那契數列中的位置,爲什麼是F[k] - 1,而不是F[k],是因爲能否用斐波那契查找法是由F[k]-1決定的,而不是F[k]。如果暫時不理解,繼續看下面。

第二個問題:a的長度其實很好估算,比如你定義了有10個元素的有序數組a[10],n=10,那麼n就位於8和13,即F[6]和F[7]之間,所以 k=7,此時數組a的元素個數要被擴充,爲:F[7] - 1 = 12個; 再如你定義了一個b[12],且b有12個元素,即n=12,那麼很好辦了,n = F[7]-1 = 12, 用不着擴充了; 又或者n=8或9或11,則它一定會被擴充到12; 再如你舉的例子,n=13,最後得出n位於13和21,即F[7]和F[8]之間,此時k=8,那麼F[8]-1 = 20,數組a就要有20個元素了。 所以,n = x(13<=x<=20)時,最後都要被擴充到20;類推,如果n=25呢,則數組a的元素個數肯定要被擴充到 34 - 1 = 33個(25位於21和34,即F[8]和F[9]之間,此時k=9,F[9]-1 = 33),所以,n = x(21<=x<=33)時,最後都要被擴充到33。也就是說,最後數組的元素個數一定是(某個斐波那契數 - 1),這就是一開始說的n與F[k]-1的關係。

第三個問題:對於二分查找,分割是從mid= (low+high)/2開始;而對於斐波那契查找,分割是從mid = low + F[k-1] - 1開始的; 通過上面知道了,數組a現在的元素個數爲F[k]-1個,即數組長爲F[k]-1,mid把數組分成了左右兩部分, 左邊的長度爲:F[k-1] - 1, 那麼右邊的長度就爲(數組長-左邊的長度-1), 即:(F[k]-1) - (F[k-1] - 1) = F[k] - F[k-1] - 1 = F[k-2] - 1。 
斐波那契查找的核心是:
  1)當key=a[mid]時,查找成功;
  2)當key<a[mid]時,新的查找範圍是第low個到第mid-1個,此時範圍個數爲F[k-1] - 1個,即數組左邊的長度,所以要在[low, F[k - 1] - 1]範圍內查找;
  3)當key>a[mid]時,新的查找範圍是第mid+1個到第high個,此時範圍個數爲F[k-2] - 1個,即數組右邊的長度,所以要在[F[k - 2] - 1]範圍內查找。

附:

    上文中不明白之處在於    “如果一個有序表的元素個數爲n,並且n正好是(某個斐波那契數 - 1),即n=F[k]-1時,才能用斐波那契查找法。 如果有序表的元素個n不等於(某個斐波那契數 - 1),即n≠F[k]-1,這時必須要將有序表的元素擴展到大於n的那個斐波那契數 - 1才行”,爲什麼要n=F[k]-1??數學底子比較差,沒法給出數學證明。。。其次就是最後,數組分爲兩部分中左邊長度爲:F[k-1]-1,不知道爲什麼一定要是該值難道F[k-1]不可以嗎??

文章轉自http://blog.chinaunix.net/uid-27164517-id-3313988.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章