费氏搜索浅谈

说明:

二分搜尋法每次搜尋時,都會將搜尋區間分為一半,所以其搜尋時間為O(log(2)n),log(2)表示以2為底的log值,

這邊要介紹的費氏搜尋,其利用費氏數列作為間隔來搜尋下一個數,所以區間收斂的速度更快,搜尋時間為O(logn)。

解法:

費氏搜尋使用費氏數列來決定下一個數的搜尋位置,所以必須先製作費氏數列,這在之前有提過;費氏搜尋會先透過公式計算求出第一個要搜尋數的位置,以及其代表的費氏數,以搜尋對象10個數字來說,第一個費氏數經計算後一定是F5,而第一個要搜尋的位置有兩個可能,例如若在下面的數列搜尋的話(為了計算方便,通常會將索引0訂作無限小的數,而數列由索引1開始):

-∞ 1 3 5 7 9 13 15 17 19 20

如果要搜尋5的話,則由索引F5F5表示第五個費式數作為索引,也就是5)開始搜尋,接下來如果數列中的數大於指定搜尋值時,就往左找,小於時就向右,每次找的間隔是F4(第四個費式數作為索引,也就是3)、F3(第三個費式數作為索引,也就是2)、F2(第二個費式數作為索引,也就是1)
來尋找,當費氏數為0時還沒找到,就表示尋找失敗,如下所示:
費式搜尋

如果要搜尋19,由於第一個搜尋值索引F5處的值小於19,所以此時必須對齊數列右方,也就是將第一個搜尋值的索引改為F5+2 = 7,然後如同上述的方式進行搜尋,如下所示:
費式搜尋
至於第一個搜尋值是如何找到的?我們可以由以下這個公式來求得,其中n為搜尋對象的個數,Fy為第y個費式數,必須大於等於n,若算出x值,則使用Fx作為第一個搜尋索引,也就是第x個費式數:
Fy + m = n
Fy
>= n + 1
x = y - 1

以10個搜尋對象來說:
Fy + m = 10

Fy = 8, m = 2,所以可以對照費氏數列得到8是第六個費式數,所以y=6,所以x得5,也就是使用第五個費式數的值(也就是5)作為索引開始搜尋。

如果數列在索引5處的值大於指定的搜尋值,則第一個搜尋位置就是索引5的位置,如果小於指定的搜尋值,則第一個搜尋位置必須加上m,也就是F5 + m = 5 + 2 = 7,也就是索引7的位置,其實加上m的原因,是為了要讓下一個搜尋值剛好是數列的最後一個位置。

費氏搜尋看來難懂,但只要掌握Fy + m = n這個公式,自己找幾個實例算一次,很容易就可以理解;費氏搜尋除了收斂快速之外,由於其本身只會使用到加法與減法,在運算上也可以加快。


//建立费氏数列
void createfib()
{
      int i;
      Fib[0] = 0;
      Fib[1] = 1;
      for(i = 2; i < MAX;i++)
           Fib[i] = Fib[i-1] + Fib[i-2];
}

//找x值
int findx(int n,int find)
{
      int i = 0;
      while(Fib[i] <= n)
      i++;
      return --i;
}
//费氏搜寻
int fibsearch(int number[],int find)
{
        int i ,x,m;
        createfib();
        x = findx(MAX+1,find);
        m = MAX - Fib[x];
        printf("\nx=%d,m = %d,Fib[x] = %d\n\n",x,m,Fib[x]);
        x--;
       i = x;

//费氏搜索关键代码
      if(number[i] < find)
             i += m;
      while(Fib[x] > 0)
      {
           if(number[i] < find)
                  i +=Fib[--x];
           else
                if(number[i] > find)
                       i -= Fib[--x];
               else
                      return i;
 
        }
       return -1;
}

原文地址:https://www.cnblogs.com/LUO257316/p/3220874.html