# “斐波那契查找”真的比“二分查找”快么？

43 篇文章 1 订阅
Is Fibonacci Search really "faster" than Binary Search?

1. 介绍

F(0) = 0，F(1)=1，F(n)=F(n-1)+F(n-2) (n≥2)，显然这是一个线性递推数列,随着数列项数的增加，前一项与后一项之比越来越逼近黄金分割的数值0.6180339887..…

### The Fibonacci Search Algorithm

Let Fk represent the k-th Fibonacci number where Fk+2=Fk+1 + Fk for k>=0 and F0 = 0, F1 = 1. To test whether an item is in a list of n = Fm ordered numbers, proceed as follows:

1. Set k = m.
2. If k = 0, finish - no match.
3. Test item against entry in position Fk-1.
4. If match, finish.
5. If item is less than entry Fk-1, discard entries from positions Fk-1 + 1 to n. Set k = k - 1 and go to 2.
6. If item is greater than entry Fk-1, discard entries from positions 1 to Fk-1. Renumber remaining entries from 1 to Fk-2, set k = k - 2 and go to 2.

If n is not a Fibonacci number, then let Fm be the smallest such number >n, augment the original array with Fm-n numbers larger than the sought item and apply the above algorithm for n'=Fm.

2.实验

实验数据：产生有序数组
 1 2 3 4 5 6 #define NUM  4 int *array = ( int *)calloc(NUM,  sizeof( int)); for ( int i =  0; i < NUM; ++i) {     array[i] = i; }

实验方法：三种搜索算法函数原型pData-数组，n-数组个数，key-待搜索关键字
 1 2 3 4 int LineSearch( int *pData,  int n,  int key); int BinarySearch( int *pData,  int n,  int key); int FibonacciSearch( int *pData,  int n,  int key);

线性查找
 1 2 3 4 5 6 7 8 9 10 11 int LineSearch( int *pData,  int n,  int key) {      int idx =  0;      while(idx != n )     {          if(pData[idx] != key)             idx++;          else              return idx;     } }

二分查找
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int BinarySearch( int *pData,  int n,  int key) {      int center, left =  0, right = n -  1;      while(left <= right)     {         center = (left + right) /  2;          if (pData[center] > key)         {             right = center -  1;         }          else         {              if (pData[center] < key)                 left = center +  1;              else                  return center;         }     }      return - 1; }

斐波那契查找
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 /*   Fibonaccian search for locating the index of "key" in an array "pData" of size "n"   that is sorted in ascending order. See http://doi.acm.org/10.1145/367487.367496   Algorithm description   -----------------------------------------------------------------------------   Let Fk represent the k-th Fibonacci number where Fk+2=Fk+1 + Fk for k>=0 and   F0 = 0, F1 = 1. To test whether an item is in a list of n = Fm ordered numbers,   proceed as follows:   a) Set k = m.   b) If k = 0, finish - no match.   c) Test item against entry in position Fk-1.   d) If match, finish.   e) If item is less than entry Fk-1, discard entries from positions Fk-1 + 1 to n.      Set k = k - 1 and go to b).   f) If item is greater than entry Fk-1, discard entries from positions 1 to Fk-1.      Renumber remaining entries from 1 to Fk-2, set k = k - 2 and go to b)   If Fm>n then the original array is augmented with Fm-n numbers larger   than key and the above algorithm is applied.  */ int FibonacciSearch( int *pData,  int n,  int key) {      register  int k, idx, offs;      static  int prevn = - 1, prevk = - 1;      /*  Precomputed Fibonacci numbers F0 up to F46. This implementation assumes that the size n      *  of the input array fits in 4 bytes. Note that F46=1836311903 is the largest Fibonacci      *  number that is less or equal to the 4-byte INT_MAX (=2147483647). The next Fibonacci      *  number, i.e. F47, is 2971215073 and is larger than INT_MAX, implying that it does not      *  fit in a 4 byte integer. Note also that the last array element is INT_MAX rather than      *  F47. This ensures correct operation for n>F46.      */      const  static  int Fib[ 47 +  1] = { 0,  1,  1,  2,  3,  5,  8,  13,  21,  34,  55,  89,  144,  233,  377,  610,  987,  1597,  2584,  4181,  6765,                                      10946,  17711,  28657,  46368,  75025,  121393,  196418,  317811,  514229,  832040,  1346269,  2178309,  3524578,                                      5702887,  9227465,  14930352,  24157817,  39088169,  63245986,  102334155,  165580141,  267914296,                                      433494437,  701408733,  1134903170,  1836311903, INT_MAX                                    };      /* find the smallest fibonacci number that is greater or equal to n. Store this      * number to avoid recomputing it in the case of repetitive searches with identical n.      */      if(n != prevn)     {          register  int f0, f1, t;          for(f0 =  0, f1 =  1, k =  1; f1 < n; t = f1, f1 += f0, f0 = t, ++k);         prevk = k;         prevn = n;     }      else         k = prevk;      /* If the sought value is larger than the largest Fibonacci number less than n,      * care must be taken top ensure that we do not attempt to read beyond the end      * of the array. If we do need to do this, we pretend that the array is padded      * with elements larger than the sought value.      */      for(offs =  0; k >  0;  )     {         idx = offs + Fib[--k];          /* note that at this point k  has already been decremented once */          if(idx >= n || key < pData[idx])  // index out of bounds or key in 1st part         {              continue;         }          else  if (key > pData[idx])         {              // key in 2nd part             offs = idx;             --k;         }          else  // key==pData[idx], found              return idx;     }      return - 1;  // not found }

C++ Code
 1 2 3 printf( "LineSearch Index : %d\n", LineSearch(array, NUM, array[ 3])); printf( "BinarySearch Index : %d\n", BinarySearch(array, NUM, array[ 3])); printf( "FibonacciSearch Index : %d\n", FibonacciSearch(array, NUM, array[ 3]));

 （NUM=4） 0 1 2 3 total Line 0 1 2 3 7 Binary 1 0 1 2 4 Fibonacci 4 2 1 0 7
ps:第一行为待查找的关键值，本文将遍历序数组中的每个关键值的查找次数并相加（如果要表征平均，除以NUM即可，因为一样，所以就不除了），来表征平均搜索效率，因为当假设每个值被查找的概率相同，即符合均匀分布，还是有一定的合理性的。即total值越小，对单个关键值的搜索次数约有效率。

 NUM 4 40 400 4000 40000 4E5 4E6 4E7 Line 6 780 79800 7.998e+06 7.9998e+07 - - - Binary 4 143 2687 39917 534481 6675732 (0.07s) 79805719 (0.81s) 932891163 (20.34s) Fibonacci 7 179 3189 42428 572324 7206170 (0.06s) 86747879 (0.77s) 1012299070 (12.31s)
ps:E为以10为底的指数。-表示int已经不能满足要求了，溢出鸟。（）中为耗时（平台：gcc+sublime text2）。

Reference:

Search.h
 1 2 3 4 5 6 7 8 9 10 11 #include  #include  #include  #include  #define NUM  4 int LineSearch( int* pData,  int n,  int key); int BinarySearch( int* pData,  int n,  int key); int FibonacciSearch( int* pData,  int n,  int key);

Search.c
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 #include  "search.h" //四种搜索算法 搜索遍历 有序数组所用的总次数 int main( int argc,  char  const *argv[]) {     clock_t start, finish;      double time_duration;      //产生有序数组      int *array = ( int *)calloc(NUM,  sizeof( int));      for ( int i =  0; i < NUM; ++i)     {         array[i] = i;     }     start = clock();      int tTmp;      //线性查找     tTmp =  0;      for ( int i =  0; i < NUM; ++i)     {         tTmp += LineSearch(array, NUM, array[i]);     }     printf( "LineSearch Index : %d\n", tTmp);      //二分查找     tTmp =  0;      for ( int i =  0; i < NUM; ++i)     {         tTmp += BinarySearch(array, NUM, array[i]);     }     printf( "BinarySearch Index : %d\n", tTmp);      //斐波那契查找     tTmp =  0;      for ( int i =  0; i < NUM; ++i)     {         tTmp += FibonacciSearch(array, NUM, array[i]);     }     printf( "FibonacciSearch Index : %d\n", tTmp);     free(array);     finish = clock();     time_duration = ( double)(finish - start) / CLOCKS_PER_SEC;     printf( "Times Cost : %.2f \n", time_duration );      return  0; } int LineSearch( int *pData,  int n,  int key) {      int idx =  0;      int times =  0;      while(idx != n )     {          if(pData[idx] != key)             times++, idx++;          else              return times;     }      return - 1; } int BinarySearch( int *pData,  int n,  int key) {      int center, left =  0, right = n -  1;      int times =  0;      while(left <= right)     {         center = (left + right) /  2;          if (pData[center] > key)         {             times++, right = center -  1;         }          else         {              if (pData[center] < key)                 times++, left = center +  1;              else                  return times;         }     }      return - 1; } /*   Fibonaccian search for locating the index of "key" in an array "pData" of size "n"   that is sorted in ascending order. See http://doi.acm.org/10.1145/367487.367496   Algorithm description   -----------------------------------------------------------------------------   Let Fk represent the k-th Fibonacci number where Fk+2=Fk+1 + Fk for k>=0 and   F0 = 0, F1 = 1. To test whether an item is in a list of n = Fm ordered numbers,   proceed as follows:   a) Set k = m.   b) If k = 0, finish - no match.   c) Test item against entry in position Fk-1.   d) If match, finish.   e) If item is less than entry Fk-1, discard entries from positions Fk-1 + 1 to n.      Set k = k - 1 and go to b).   f) If item is greater than entry Fk-1, discard entries from positions 1 to Fk-1.      Renumber remaining entries from 1 to Fk-2, set k = k - 2 and go to b)   If Fm>n then the original array is augmented with Fm-n numbers larger   than key and the above algorithm is applied.  */ int FibonacciSearch( int *pData,  int n,  int key) {      register  int k, idx, offs;      static  int prevn = - 1, prevk = - 1;      int times =  0;      /*  Precomputed Fibonacci numbers F0 up to F46. This implementation assumes that the size n      *  of the input array fits in 4 bytes. Note that F46=1836311903 is the largest Fibonacci      *  number that is less or equal to the 4-byte INT_MAX (=2147483647). The next Fibonacci      *  number, i.e. F47, is 2971215073 and is larger than INT_MAX, implying that it does not      *  fit in a 4 byte integer. Note also that the last array element is INT_MAX rather than      *  F47. This ensures correct operation for n>F46.      */      const  static  int Fib[ 47 +  1] = { 0,  1,  1,  2,  3,  5,  8,  13,  21,  34,  55,  89,  144,  233,  377,  610,  987,  1597,  2584,  4181,  6765,                                      10946,  17711,  28657,  46368,  75025,  121393,  196418,  317811,  514229,  832040,  1346269,  2178309,  3524578,                                      5702887,  9227465,  14930352,  24157817,  39088169,  63245986,  102334155,  165580141,  267914296,                                      433494437,  701408733,  1134903170,  1836311903, INT_MAX                                    };      /* find the smallest fibonacci number that is greater or equal to n. Store this      * number to avoid recomputing it in the case of repetitive searches with identical n.      */      if(n != prevn)     {          register  int f0, f1, t;          for(f0 =  0, f1 =  1, k =  1; f1 < n; t = f1, f1 += f0, f0 = t, ++k);         prevk = k;         prevn = n;     }      else         k = prevk;      /* If the sought value is larger than the largest Fibonacci number less than n,      * care must be taken top ensure that we do not attempt to read beyond the end      * of the array. If we do need to do this, we pretend that the array is padded      * with elements larger than the sought value.      */      for(offs =  0; k >  0;  )     {         idx = offs + Fib[--k];          /* note that at this point k  has already been decremented once */          if(idx >= n || key < pData[idx])  // index out of bounds or key in 1st part         {             times++;              continue;         }          else  if (key > pData[idx])         {              // key in 2nd part             times++;             offs = idx;             --k;         }          else  // key==pData[idx], found              return times;     }      return - 1;  // not found }

• 7
点赞
• 4
评论
• 0
收藏
• 打赏
• 扫一扫，分享海报

03-01 630

05-15 1万+
08-14 3148
09-25 532
04-07 7364
09-22 3933
07-16 2万+
06-11 1万+
09-04 799
02-15 6040
03-31 881
04-29 153

fovwin

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。