斐波那契查找(超详解)

    // 斐波那契查找.cpp
    #include  <iostream>
    #include <string.h>
    using namespace std;  

    const int max_size=20;//斐波那契数组的长度  

    /*构造一个斐波那契数组*/
void Fibonacci(int * F)
{
        F[0]=0;
        F[1]=1;
        for(int i=2;i<max_size;++i)
            F[i]=F[i-1]+F[i-2];
}  

    /*定义斐波那契查找法*/
 int Fibonacci_Search(int *a, int n, int key)  //a为要查找的数组,n为要查找的数组长度,key为要查找的关键字
 {
      int low=0;
      int high=n-1;  

      int F[max_size];
      Fibonacci(F);//构造一个斐波那契数组F   

      int k=0;
      while(n>F[k]-1)//计算n位于斐波那契数列的位置
          ++k;  

      int  * temp;//将数组a扩展到F[k]-1的长度
      temp=new int [F[k]-1];
      memcpy(temp,a,n*sizeof(int));
/*
      strcpy和memcpy主要有以下3方面的区别。
    1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
    2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
    3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
    4、包含在<string.h>中
    5、函数原型:void *memcpy(void *dest, const void *src, size_t n);
       功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
*/

      for(int i=n;i<F[k]-1;++i)
         temp[i]=a[n-1];
/*
    首先要明确:如果一个有序表的元素个数为n,并且n正好是(某个斐波那契数 - 1),即n=F[k]-1时,才能用斐波那契查找法。
    如果有序表的元素个n不等于(某个斐波那契数 - 1),即n≠F[k]-1,这时必须要将有序表的元素扩展到大于n的那个斐波那契数 - 1才行,
    上面for循环这段代码:便是这个作用。
 */
      while(low<=high)
      {
        int mid=low+F[k-1]-1;
        if(key<temp[mid])
        {
          high=mid-1;
          k-=1;
        }
        else if(key>temp[mid])
        {
         low=mid+1;
         k-=2;
        }
        else
        {
           if(mid<n)
               return mid; //若mid<n则说明mid即为查找到的位置
           else
               return n-1; //若mid>=n则说明是扩展的数值,返回n-1
        }
      }
/*
      斐波那契查找方法的核心代码就是上面一段
      原理:
        1)当key=a[mid]时,查找成功;
        2)当key<a[mid]时,新的查找范围是第low个到第mid-1个,此时范围个数为F[k-1] - 1个,即数组左边的长度,
           所以要在[low, F[k - 1] - 1]范围内查找;
        3)当key>a[mid]时,新的查找范围是第mid+1个到第high个,此时范围个数为F[k-2] - 1个,即数组右边的长度,
           所以要在[F[k - 2] - 1]范围内查找。
        4)    对于二分查找,分割是从mid= (low+high)/2开始;而对于斐波那契查找,分割是从mid = low + F[k-1] - 1开始的;
            通过上面知道了,数组a现在的元素个数为F[k]-1个,即数组长为F[k]-1,mid把数组分成了左右两部分,
            左边的长度为:F[k-1] - 1, 那么右边的长度就为(数组长-左边的长度-1),
            即:(F[k]-1) - (F[k-1] - 1) = F[k] - F[k-1] - 1 = F[k-2] - 1。
*/
      delete [] temp;  //释放new出来的内存,因为是数组,所以才去delete [] temp的方式而不是delete temp.
      return -1;
 }  

int main()
{
        //int a[] = {0,10,24,35,47,59,62,73,88,99};
        int a[]= {05,13,19,21,37,56,64,75,80,88,92};
        int key=21;
        int index=Fibonacci_Search(a,sizeof(a)/sizeof(int),key);
        /*
        这里插入讨论一下数组的长度问题:
        1、char a[]=""类型的字符串,编译器会在结尾自动添加\0,用sizeof计算会算上‘\0‘
        2、存在的C语言方法,如strlen(s),计算字符串的长度,其中s指针。strlen要计算字符串长度,
           必须知道哪里是结尾,因此使用\0表示结尾。只有字符数组才有\0的概念,其它类型(int)的数组没有这个概念。
           如int a[]={} 知道数组长度使用sizeof(a)/sizeof(int);
        3、那么问题来了char a[]={}这种类型的字符串,用用sizeof计算会不会算上‘\0‘?
            答案是不会的。
        */

        cout<<key<<" is located at:"<<index<<endl;
        system("PAUSE");
        return 0;
}  

/*
        1、这里我首先建立了一个11个元素的数组a[],n=11,那么n就位于8和13,即F[6]和F[7]之间,所以 k=7,
            此时数组a的元素个数要被扩充,为:F[7] - 1 = 12个
            (这里如果问我为什么要扩充为F[k]-1而不是F[k],先留个问号,可以参考http://www.360doc.com/content/14/0528/10/14505022_381653345.shtml)
        2、然后根据核心代码开始找数:我们要找值为13的元素
           斐波那契数列前几位:0、1、1、2、3、5、8、13
           1)mid=low+F[k-1]-1  则mid=7;
           2)比较得key<temp[mid],则high=mid-1;  k-=1;  即有high=6,k=6
           3)入循环,mid=0+5-1=4;
           4)比较得key<temp[mid],则high=mid-1;  k-=1;,则有high=3,k=5
           3)入循环,mid=0+3-1=2;
           4)比较得key<temp[mid],则high=mid-1;  k-=1;,则有high=1,k=4
           5)入循环,mid=0+2-1=1;
           6)知道mid<n,得到位置为1

          3、最重要的是理解斐波那契查找的理念,让mid保持在数组的黄金分割点处,像一开始时,mid前面长度为F[K-1]-1,后面长度为F[K-2]-1,数组总长度为F[K]-1,mid       在黄金分割点。
*/
/*

    与二分查找比较:

①斐波那契查找的平均性能比折半查找好,②但最坏情况下性能却比折半查找差,③它还有一个优点就是分割时只需进行加减运算。"
    与二分查找相比,斐波那契查找算法的明显优点在于它只涉及加法和减法运算,而不用除法。
    因为除法比加减法要占去更多的机时,因此,斐波那契查找的平均性能要比折半查找好。
*/
时间: 2024-12-22 22:36:44

斐波那契查找(超详解)的相关文章

斐波那契查找原理详解与实现

最近看见一个要求仅使用加法减法实现二分查找的题目,百度了一下,原来要用到一个叫做斐波那契查找的的算法.查百度,是这样说的: 斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的.他要求开始表中记录的个数为某个斐波那契数小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说明待查找的元素在

数据结构(六)查找---有序表查找(三种查找方式:折半,插值,斐波拉契查找)

前提 有序表查找要求我们的数据是有序的,是排序好的,我们只需要进行查找即可 我们下面将介绍折半查找(二分查找),插值查找,斐波那契查找 一:折半查找 (一)定义 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列. (二)查找过程 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用中间位置记录将表分成前.后两个子表,如果中间位置记录的关

二分查找和斐波那契查找

二分查找 说明:查找的数组或列表必须是有序的,若无序,先进行排序 复杂度:时间复杂度 O(log2n),空间复杂度O(n) C++源码(递归和非递归两个版本) #include <iostream> using namespace std; int a[] = { 1, 2, 3, 4, 5, 6, 8 }; int BinarySearch1(int l, int r, int value) { int mid = (l + r) / 2; if (l == r && a[l

数据结构之---C语言实现斐波那契查找

斐波那契查找的核心思想是: 1)当key=a[mid]时,查找成功: 2)当key<a[mid]时,新的查找范围是第low个到第mid-1个,此时范围个数为F[k-1] - 1个,即数组左边的长度,所以要在[low, F[k - 1] - 1]范围内查找: 3)当key>a[mid]时,新的查找范围是第mid+1个到第high个,此时范围个数为F[k-2] - 1个,即数组右边的长度,所以要在[F[k - 2] - 1]范围内查找. 代码: //斐波那契查找 //杨鑫 #include <

斐波那契查找算法完整C代码

/* 斐波那契查找法 */ #include <stdio.h> #include <stdlib.h> int Fib( int k ) { if( 1 == k || 2 == k ) return 1; else return Fib(k-1)+Fib(k-2); } int FibSearch( int *a, int n, int key ) { int k = 1; int nFib; int *b; int low, mid, high; while( Fib(k)

"二分查找(Binary Search)"与"斐波那契查找(Fibonacci Search)"

首先,我们来看一个笔者的拙作,一段二分查找代码 //返回值是key的下标,如果A中不存在key则返回-1 template <class T> int BinSearch(T* A, const T &key, int lo, int hi) {     int mid;     while(lo<hi)     {         mid = lo + (hi-lo)/2;         if(key < A[mid])             hi = mid-1;

(java)有序表查找——折半查找,插值查找,斐波那契查找

有序表查找 /* 主函数 */ public class OrderTableSearch { public static void main(String[] args) { int [] a= {0,1,16,24,35,47,59,62,73,88,99}; System.out.println(FibonacciSearch(a, 10, 88)); System.out.println(InsertKeySearch(a, 10, 88)); System.out.println(Bi

斐波那契查找

斐波那契查找又称为黄金比例分割查找, 大家记不记得斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(从第三个数开始,后边每一个数都是前两个数的和) 然后我们会发现,随着斐波那契数列的递增,前后两个数的比值会越来越接近0.618,利用这个特性,我们就可以将黄金比例运用到查找技术中. 黄金比例又称黄金分割,是指事物各部分间一定的数学比例关系,即将整体一分为二,较大部分与较小部分之比等于整体与较大部分之比,其比值约为1:0.618或1.618:1. 0.61

斐波那契查找法

void Fibonacci(int *f) { f[0] = 1; f[1] = 1; for (int i = 2; i < MAXSIZE; i++) { f[i] = f[i - 1] + f[i - 2]; } } int Fibonacci_Search(int *a, int n, int key) { int low, high, mid; low = 1; high = n - 1; int k = 0; int F[MAXSIZE]; Fibonacci(F); //问题一: