顺序,二分,插值,斐波那契 查找算法

总结:

博客详细描述:(http://www.cnblogs.com/maybe2030/p/4715035.html#_label4

关注:

  1. 二分查找、插值查找以及斐波那契查找都可以归为一类插值查找;
  2. 插值查找和斐波那契查找是在二分查找的基础上的优化;
  3. 但由于数组中数据分布非常不均匀,所以插值查找效率未必好;
  4. 二分查找在静态查找表,一次排序后不再变化,得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。——《大话数据结构》

时间复杂度:

顺序查找:O(n)
二分查找:O(log2(n+1)) – O(log2n)
插值查找:O(log2(log2n))
斐波那契查找:O(log2n)

查找定义:

根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。

查找算法分类:

  1. 静态查找和动态查找;
    注:静态或者动态都是针对查找表而言的。动态表指查找表中有删除和插入操作的表。
  2. 无序查找和有序查找。
    无序查找:被查找数列有序无序均可;
    有序查找:被查找数列必须为有序数列。

顺序查找

  1. 说明:
    顺序查找适合于存储结构为顺序存储链接存储的线性表。
  2. 时间复杂度分析:
    查找成功时的平均查找长度为:ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;时间复杂度为O(n)。
//顺序查找
int SequenceSearch(int a[], int value, int n)
{
    int i;
    for(i=0; i<n; i++)
        if(a[i]==value)
            return i;
    return -1;
}

二分查找(折半查找)

  1. 说明:
    也称为折半查找,属于有序查找算法。
  2. 时间复杂度分析:
    最坏情况下,关键词比较次数为log2(n+1),且期望(最好)时间复杂度为O(log2n);
  3. 优缺点:
    折半查找的前提条件是需要有序表顺序存储,静态查找表,一次排序后不再变化,折半查找能得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。——《大话数据结构》
//二分查找(折半查找),版本1
int BinarySearch1(int a[], int value, int n)
{
    int low, high, mid;
    low = 0;
    high = n-1;
    while(low<=high)
    {
        mid = (low+high)/2;
        if(a[mid]==value)
            return mid;
        if(a[mid]>value)
            high = mid-1;
        if(a[mid]<value)
            low = mid+1;
    }
    return -1;
}

//二分查找,递归版本
int BinarySearch2(int a[], int value, int low, int high)
{
    int mid = low+(high-low)/2;
    if(a[mid]==value)
        return mid;
    if(a[mid]>value)
        return BinarySearch2(a, value, low, mid-1);
    if(a[mid]<value)
        return BinarySearch2(a, value, mid+1, high);
}

插值查找

  1. 说明:
    比如要在取值范围1 ~ 10000 之间 100 个元素从小到大均匀分布的数组中查找5, 我们自然会考虑从数组下标较小的开始查找。
    折半查找:mid=low+1/2*(high-low);
    插值查找:mid=low+(key-a[low])/(a[high]-a[low])*(high-low);

  2. 时间复杂度分析:
    查找成功或者失败的时间复杂度均为O(log2(log2n))

  3. 优缺点:
    对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。
int insertSearch(int *sortedSeq, int seqLength , int keyData)
{
    int low = 0, mid, high = seqLength - 1;

    while (low <= high)
    {
        mid = low + (keyData - sortedSeq[low]) / (sortedSeq[high] - sortedSeq[low]);
        if (keyData < sortedSeq[mid])
        {
            high = mid - 1;//是mid-1,因为mid已经比较过了
        }
        else if (keyData > sortedSeq[mid])
        {
            low = mid + 1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}

斐波那契查找

  1. 说明:
    二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找。
    什么是黄金分割?
    黄金比例又称黄金分割,是指事物各部分间一定的数学比例关系,即将整体一分为二,较大部分与较小部分之比等于整体与较大部分之比,其比值约为1:0.618或1.618:1。
    0.618被公认为最具有审美意义的比例数字,这个数值的作用不仅仅体现在诸如绘画、雕塑、音乐、建筑等艺术领域,而且在管理、工程设计等方面也有着不可忽视的作用。
    斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….

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

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

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

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

  while(low<=high)
  {
    int mid=low+F[k-1]-1;
    if(key<a[mid])
    {
      high=mid-1;
      k-=1;
    }
    else if(key>a[mid])
    {
     low=mid+1;
     k-=2;
    }
    else
    {
       if(mid<n)
           return mid; //若相等则说明mid即为查找到的位置
       else
           return n-1; //若mid>=n则说明是扩展的数值,返回n-1
    }
  }
  return -1;
}
    原文作者:查找算法
    原文地址: https://blog.csdn.net/cy_cai/article/details/53230787
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞