说明:
二分搜尋法每次搜尋時,都會將搜尋區間分為一半,所以其搜尋時間為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的話,則由索引F5(F5表示第五個費式數作為索引,也就是5)開始搜尋,接下來如果數列中的數大於指定搜尋值時,就往左找,小於時就向右,每次找的間隔是F4(第四個費式數作為索引,也就是3)、F3(第三個費式數作為索引,也就是2)、F2(第二個費式數作為索引,也就是1)來尋找,當費氏數為0時還沒找到,就表示尋找失敗,如下所示:
Fy >= n + 1
x = y - 1
以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;
}