阿牧路泽

哪有那么多坚强,无非是死扛罢了
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

13、【查找算法】斐波那契查找

Posted on 2018-10-16 17:07  阿牧路泽  阅读(492)  评论(0编辑  收藏  举报

斐波那契查找

  在介绍斐波那契查找算法之前,我们先介绍一下很它紧密相连并且大家都熟知的一个概念——黄金分割。

  黄金比例又称黄金分割,是指事物各部分间一定的数学比例关系,即将整体一分为二,较大部分与较小部分之比等于整体与较大部分之比,其比值约为1:0.618或1.618:1。

  0.618被公认为最具有审美意义的比例数字,这个数值的作用不仅仅体现在诸如绘画、雕塑、音乐、建筑等艺术领域,而且在管理、工程设计等方面也有着不可忽视的作用。因此被称为黄金分割。

  大家记不记得斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(从第三个数开始,后边每一个数都是前两个数的和)。然后我们会发现,随着斐波那契数列的递增,前后两个数的比值会越来越接近0.618,利用这个特性,我们就可以将黄金比例运用到查找技术中。

  基本思想:也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。
  相对于折半查找,一般将待比较的key值与第mid=(low+high)/2位置的元素比较,比较结果分三种情况:

  1)相等,mid位置的元素即为所求

  2)>,low=mid+1;

     3)<,high=mid-1。

  斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小1,及n=F(k)-1;

 开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种

  1)相等,mid位置的元素即为所求

  2)>,low=mid+1,k-=2;

  说明:low=mid+1说明待查找的元素在[mid+1,high]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找。

  3)<,high=mid-1,k-=1。

  说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1个,所以可以递归 的应用斐波那契查找。

  复杂度分析:最坏情况下,时间复杂度为O(log2n),且其期望复杂度也为O(log2n)。

C++实现源码:

  1 //斐波那契查找
  2 #include <iostream>
  3 #include <stdlib.h>
  4 #include <stdio.h>
  5 #include <cstring>
  6 #include <ctime>
  7 
  8 using namespace std;
  9 
 10 #define MAX 100
 11 #define max_size 150
 12 
 13 //数组输入
 14 void input(int *arr)
 15 {
 16     srand((unsigned)time(NULL));
 17     for(int i = 0; i < MAX; i++)
 18     {
 19         arr[i] = rand()%100;
 20     }
 21 }
 22 //数组输出
 23 void output(int *arr)
 24 {
 25     for(int i = 0; i < MAX; i++)
 26     {
 27         printf("%5d", arr[i]);
 28         if(0 == (i+1) % 10)
 29             cout << endl;
 30     }
 31     cout << endl;
 32 }
 33 //快速排序
 34 void quickSort(int *arr, int l, int h)
 35 {
 36     if(l < h)
 37     {
 38         int low, high, tmp;
 39         low = l;
 40         high = h;
 41 
 42         tmp = arr[l];//选择基准值
 43         //将数组按照基准值分为两部分
 44         while(low < high)
 45         {
 46             while(low < high && arr[high] > tmp)
 47                 high--;
 48             if(low < high)
 49                 arr[low++] = arr[high];
 50             while(low < high && arr[low] < tmp)
 51                 low++;
 52             if(low < high)
 53                 arr[high--] = arr[low];
 54         }
 55         arr[low] = tmp;
 56         //递归排序
 57         quickSort(arr, l, low-1);
 58         quickSort(arr, low+1, h);
 59     }
 60 }
 61 //构造一个斐波那契数组
 62 void fibonacci(int * F)
 63 {
 64     F[0] = 0;
 65     F[1] = 1;
 66     for(int i = 2; i < max_size; i++)
 67         F[i] = F[i-1] + F[i-2];
 68 }
 69 //斐波那契查找
 70 int fibonacciSearch(int *arr, int len, int value)
 71 {
 72     int low = 0;
 73     int high = len-1;
 74 
 75     int F[max_size];
 76     fibonacci(F);//构造一个斐波那契数组
 77 
 78     int k = 0;
 79     while(len > F[k]-1)//计算n位于斐波那契数组中的位置
 80         k++;
 81 
 82     int *temp;//将数组arr扩展到F[k]-1长度
 83 
 84     temp=new int [F[k]-1];
 85     memcpy(temp, arr, len*sizeof(int));
 86 
 87     for(int i = len; i < F[k]-1; i++)
 88         temp[i] = arr[len-1];
 89 
 90     while(low < high)
 91     {
 92         int mid = low + F[k-1]-1;
 93         if(value < temp[mid])
 94         {
 95             high = mid -1;
 96             k -= 1;
 97         }
 98         else if(value > temp[mid])
 99         {
100             low = mid+1;
101             k -= 2;
102         }
103         else
104         {
105             if(mid < len)
106                 return mid;
107             else
108                 return len-1;
109         }
110     }
111     delete[] temp;
112     return -1;
113 }
114 
115 
116 int main()
117 {
118     int x, pos, num[MAX];
119     input(num);
120 
121     cout << "sort before:" << endl;
122     output(num);
123     quickSort(num, 0, MAX-1);
124     cout << "sort after:" << endl;
125     output(num);
126 
127     cout << "Enter find num : ";
128     cin >> x;
129 
130     pos = fibonacciSearch(num, MAX, x);
131     if(pos)
132         cout << "OK!" << x << "is found in pos : " << pos << endl;
133     else
134         cout << "Sorry!" << x << "is not found in num" << endl;
135 
136     return 0;
137 }