費氏搜尋法 (Fibonacci Search) 又稱費伯那搜尋法, 此法與二分法一樣都是以切割範圍來進行搜尋, 不同的是費氏搜尋法不以對稱(對半)切割而是以費氏及數的方式切割. 費氏級數 F(n) 定義如下 :
費氏級數 : 0,1,1,2,3,5,8,... . 也就是除了第0 及第1 個元素外, 每個值都是前兩個的值的加總. 費式搜尋法的好處是只用到加減運算而不需用到乘法及除法, 這種以電腦運算的過程來看效率會高於前兩種搜尋法 (二元搜尋法與循序搜尋法).
費式搜尋樹 :
在尚未介紹費式搜尋法之前, 我們先來認識費式搜尋樹. 所謂的費式搜尋樹是以費氏級數的特性所建立的二元樹, 其建立原則如下 :
也就是說當資料個數為 n, 且我們找到一個最小的費氏樹 Fib(k+1) 使得 Fib(k+1) > n+1. 則 Fib(k) 就是這棵費氏樹的樹根, 而 Fib(k-2) 則是與左右子樹開始的差值, 左子樹用減的 ; 右子樹用加的. 例如我們來實際求得 n = 33 的費氏樹 :
依此原則我們可以建立如下的費氏樹 :
費氏搜尋法 :
費氏搜尋法是以費氏搜尋樹來找尋資料, 如果資料的個數為 n, 而且 n 比某一費氏樹小, 且滿足如下運算式 :
Fib(k+1) >= n+1
此時 Fib(k) 就是這棵費氏樹的樹根, 而 Fib(k-2) 則是與左右子樹開始的差值, 若我們要尋找的鍵值為 key, 首先比較陣列索引 Fib(k) 和鍵值 key, 此時可以有下列三種比較情況 :
費氏法分析 :
範例代碼 :
- #include
- using namespace std;
- #define FIB_SEARCH_MAX_LEN 20
- int _fib(int n) {
- if(n == 0 || n==1)
- return n;
- return _fib(n-1) + _fib(n-2);
- }
- int fibSearch(int data[FIB_SEARCH_MAX_LEN], int key) {
- cout << "搜尋處理中(使用費氏搜尋法)..." << endl;
- int index = 2;
- // 費氏數列的 k 值計算
- while(_fib(index) <= FIB_SEARCH_MAX_LEN)
- index++;
- index--;
- printf("Using key=%d...\n", index);
- int rootNode = _fib(index);
- int diff1 = _fib(index-1); // 上一個費氏數
- int diff2 = _fib(index-2); // 上兩個費氏數
- rootNode--; // 配合陣列的索引是從 0 開始.
- printf("Root Node=%d...\n", rootNode);
- while(1) {
- printf("\tData[%d]=%d...\n", rootNode, data[rootNode]);
- if(key == data[rootNode]) {
- return rootNode;
- } else {
- if(index==2) break; // 沒有找到
- if(key < data[rootNode]) {
- rootNode = rootNode - diff2; // 左子樹的新樹根
- printf("左子樹新樹根=%d...\n", rootNode);
- int temp = diff1;
- diff1 = diff2; // 上一個費氏樹
- diff2 = temp - diff2; // 上兩個費氏樹
- index = index-1;
- } else {
- if(index==3) break; // 沒有找到
- rootNode = rootNode + diff2; // 右子樹的新樹根
- printf("右子樹新樹根=%d...\n", rootNode);
- diff1 = diff1 - diff2; // 上一個費氏樹
- diff2 = diff2 - diff1; // 上兩個費氏樹
- index = index -2;
- }
- }
- }
- return -1;
- }
- void main() {
- int data[] = {5, 7, 12, 23, 25, 37, 48, 54, 68, 77, 91, 99, 102, 110, 118, 120, 130, 135, 136, 150};
- printf("Source data:\n");
- for(int i=0; i<4; i++) {
- for(int j=0; j<5; j++)
- printf("data[%2d] = %3d\t", i*5+j, data[i*5+j]);
- printf("\n");
- }
- int key = 0, num;
- while(1) {
- cout << "請輸入搜尋值(1-150), 輸入-1結束: ";
- cin >> key;
- if(key<0)
- break;
- num = fibSearch(data, key);
- if(num>=0) {
- cout << "在第 " << num << "個位置找到 ( data[" << num << "]=" << data[num] << "." << endl;
- } else {
- cout << "##### 沒有找到 " << key << "#####" << endl;
- }
- }
- }
沒有留言:
張貼留言