斐波那契查找算法(黄金分割查找算法)
什么是斐波那契查找
斐波那契数列,又称黄金分割数列,指的是这样一个数列: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)。
对于斐波那契数列: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开始。所以用迭代实现斐波那契查找算法如下:
1 #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),但是与折半查找相比,斐波那契查找的优点是它只涉及加法和减法运算,而不用除法,而除法比加减法要占用更多的时间,因此,斐波那契查找的运行时间理论上比折半查找小,但是还是得视具体情况而定