1. 程式人生 > >使用斐波那契查詢

使用斐波那契查詢

元素的個數實質為F(n)個,前半部分元素個數為F(n-1)個,後半部分元素個數為F(n-2)個,下標從0開始,所以長度為F(n)-1,mid=low+F(n-1)-1,這裡的F(n-1)是對應的斐波那契數列中的那個值

什麼是斐波那契查詢
斐波那契數列,又稱黃金分割數列,指的是這樣一個數列:1、1、2、3、5、8、13、21、····,在數學上,斐波那契被遞迴方法如下定義:F(1)=1,F(2)=1,F(n)=f(n-1)+F(n-2) (n>=2)。該數列越往後相鄰的兩個數的比值越趨向於黃金比例值(0.618)。

 斐波那契查詢就是在二分查詢的基礎上根據斐波那契數列進行分割的。在斐波那契數列找一個等於略大於查詢表中元素個數的數F[n],將原查詢表擴充套件為長度為F[n](如果要補充元素,則補充重複最後一個元素,直到滿足F[n]個元素),完成後進行斐波那契分割,即F[n]個元素分割為前半部分F[n-1]個元素,後半部分F[n-2]個元素,找出要查詢的元素在那一部分並遞迴,直到找到。

斐波那契查詢的時間複雜度還是O(log 2 n ),但是 與折半查詢相比,斐波那契查詢的優點是它只涉及加法和減法運算,而不用除法,而除法比加減法要佔用更多的時間,因此,斐波那契查詢的執行時間理論上比折半查詢小,但是還是得視具體情況而定。
對於斐波那契數列:1、1、2、3、5、8、13、21、34、55、89……(也可以從0開始),前後兩個數字的比值隨著數列的增加,越來越接近黃金比值0.618。比如這裡的89,把它想象成整個有序表的元素個數,而89是由前面的兩個斐波那契數34和55相加之後的和,也就是說把元素個數為89的有序表分成由前55個數據元素組成的前半段和由後34個數據元素組成的後半段,那麼前半段元素個數和整個有序表長度的比值就接近黃金比值0.618,假如要查詢的元素在前半段,那麼繼續按照斐波那契數列來看,55 = 34 + 21,所以繼續把前半段分成前34個數據元素的前半段和後21個元素的後半段,繼續查詢,如此反覆,直到查詢成功或失敗,這樣就把斐波那契數列應用到查詢演算法中了。

從圖中可以看出,當有序表的元素個數不是斐波那契數列中的某個數字時,需要把有序表的元素個數長度補齊,讓它成為斐波那契數列中的一個數值,當然把原有序表截斷肯定是不可能的,不然還怎麼查詢。然後圖中標識每次取斐波那契數列中的某個值時(F[k]),都會進行-1操作,這是因為有序表陣列位序從0開始的,純粹是為了迎合位序從0開始。所以用迭代實現斐波那契查詢演算法如下:

 #include <stdio.h>  
 2   
 3 #define FIB_MAXSIZE 100  
 4   
 5 /** 
 6  * 生成斐波那契數列 
 7  * @param fib:指向儲存斐波那契數列的陣列的指標 
 8  * @param size:斐波那契數列長度 
 9  */  
10 void ProduceFib(int *fib, int size)  
11 {  
12     int i;  
13   
14     fib[0] = 1;  
15     fib[1] = 1;  
16   
17     for (i = 2; i < size; i++)  
18     {  
19         fib[i] = fib[i - 1] + fib[i - 2];  
20     }  
21 }  
22   
23 /** 
24  * 斐波那契查詢,查詢成功返回位序,否則返回-1 
25  * @param data:有序表陣列 
26  * @param length:有序表元素個數 
27  * @param searchValue:待查詢關鍵字 
28  */  
29 int FibonacciSearch(int *data, int length, int searchValue)  
30 {  
31     int low, high, mid, k, i, fib[FIB_MAXSIZE];  
32   
33     low = 0;  
34     high = length - 1;  
35   
36     ProduceFib(fib, FIB_MAXSIZE);  
37   
38     k = 0;  
39     // 找到有序表元素個數在斐波那契數列中最接近的最大數列值  
40     while (high > fib[k] - 1)  
41     {  
42         k++;  
43     }  
44   
45     // 補齊有序表  
46     for (i = length; i <= fib[k] - 1; i++)  
47     {  
48         data[i] = data[high];  
49     }  
50   
51     while (low <= high)  
52     {  
53         mid = low + fib[k - 1] - 1;   // 根據斐波那契數列進行黃金分割  
54   
55         if (data[mid] == searchValue)  
56         {  
57             if (mid <= length - 1)  
58             {  
59                 return mid;  
60             }  
61             else  
62             {  
63                 // 說明查詢得到的資料元素是補全值  
64                 return length - 1;  
65             }  
66         }  
67   
68         if (data[mid] > searchValue)  
69         {  
70             high = mid - 1;  
71             k = k - 1;  
72         }  
73   
74         if (data[mid] < searchValue)  
75         {  
76             low = mid + 1;  
77             k = k - 2;  
78         }  
79     }  
80   
81     return -1;  
82 }  
83   
84 int main()  
85 {  
86     int data[] = {1,3,5,7,9,11,13,15,17,19,21};  
87   
88     int index = FibonacciSearch(data, 11, 19);  
89     printf("%d\n", index);  
90   
91     return 0;  
92 }  

斐波那契查詢的時間複雜度還是O(log2n),但是與折半查詢相比,斐波那契查詢的優點是它只涉及加法和減法運算,而不用除法,而除法比加減法要佔用更多的時間,因此,斐波那契查詢的執行時間理論上比折半查詢小,但是還是得視具體情況而定

引自 :https://www.cnblogs.com/lpfuture/p/7112450.html