插值查找+斐波那契查找

插值查找

插值查找其实是折半查找的升级版,在我们写折半查找的时候不知道大家想过没有

为什么每次要折一半呢?1/4不行吗?1/8不行吗?这样我们就可以想到,是不是可

以找到更精准的“折半”的方式来处理呢。

在折半查找中   mid=(high+low)/2;  转化一下变成:mid=low+1/2*(high-low);

我们可以看到 “(high-low)”的系数为1/2,但是我们想找一个自适应的系数以便于找到

目标数与下标为mid所对应的数更加的接近,我们就要将这个系数更改掉,让程序自己

去找与目标数更加接近的数。

于是我们就将程序优化成    mid=low+((key-A[low])/(A[high]-A[low]))*(high-low);

这样我们就找到这个自适应的系数了,这样查找起来也就更快。

利用插值查找 :查找成功或者失败的时间复杂度均为O(log2(log2n))。

 

c++代码实现:

#include<iostream>
using namespace std;
int InsertionSearch(int A[],int high,int key,int low)//high当前数组下标的最大值,low为当前数组下标的最小值; 
{
    int mid=low+((key-A[low])/(A[high]-A[low]))*(high-low);
    if(key==A[low])
      return mid;
    if(key>A[mid])
      return InsertionSearch(A,high,key,mid+1); 
    if(key<A[mid])
      return InsertionSearch(A,mid-1,key,low);    
} 

插值查找比折半查找要快,其与折半查找的原理一样,也要求序列是有序的,

缺点也是一样,如果序列在程序运行的时候需要多次改变序列的顺序,那么

插值查找也就不再适用。

斐波那契查找

斐波那契查找也是折半查找的一种改良版;斐波那契查找最主要的就是找mid这个点;

在该种查找算法中,我们要找的mid这个点为数组中的黄金分割点,要求黄金分割点

我们就要用到斐波那契数列了;我们可以看一下这个数列:1,1,2,3,5,8,13,21,34,55..........;

可以看出俩个规律:

1:从第三项开始每一项等于它的前两项的和;

2:数列越往后,前后两项的比值越接近0.618,也就是黄金比例的比值;

利用这两个规律我们就可以来找这个黄金分割点;我们令这个数组为F[],下标为k;

斐波那契查找的核心就是在mid前面的长度为F[k-1]-1,在mid的后面的长度为F[k-2]-1;

具体步骤:(记待查找的数组为A)

1:构建斐波那契数组;

2:找到n(A数组的长度)在斐波那契数组中的位置,并将数组补全(可用A(n-1)来补);

3:计算mid=low+F(k-1)-1;

4:如果A[mid]>key(key为要查找的数)high=mid-1;k=k-1;(mid前面的长度)

5:如果A[mid[<key  low=mid+1;k=k-2(mid后面的长度);

6:如果A[mid]=key &&mid<=high 则返回下标值(即mid的值);否则查找失败;

#include<iostream>
using namespace std;
int max_size=20;
void fbnq_list(int *A)//构建斐波那契数组; 
{
    A[0]=A[1]=1;
    for(int i=2;i<20;i++)
    {
        A[i]=A[i-1]+A[i-2];
    }
}
int fbnq_search(int A[],int n,int key)
{
    int F[max_size];
    fbnq_list(F);
    int low=0;
    int high=n-1;
    int mid=0;
    int k=0;
    while(n>F[k]-1)//找出n在斐波那契数列中的位置 
        k++;
    for(int i=n;i<F[k]-1;i++)//将数组补全,大于n的下标对于的数全部为A【high】; 
        A[i]=A[high];
    while(low<=high)
    {
        mid=low+F[k-1]-1;//mid的位置为黄金分割点; 
        if(A[mid]>key)
        {
            high=mid-1;
            k=k-1;//F[k-1]-1为mid前面的元素个数; 
        }
        else if(A[mid]<key)
        {
            low=mid+1;
            k=k-2;//F[k-1] -1为mid后面的元素个数; 
        }
     else
        {
            if(mid <= high)//如果为真则找到相应的位置
                return mid;
            else
                return -1;
        }
    }
    return -1;
    
}
int main()
{
    int A[]={-1,2,3,45,54,78,95,102,158,458,1651,1656400};
    int key;
    cin>>key; 
    int x=fbnq_search(A,12,key);
    if(x!=-1) cout<<x;//输出所对应的下标; 
    else cout<<"没有该元素"; 
    return 0;
}

斐波那契查找是折半查找的升级版,那么也要求序列是有序的序列;

在最坏情况下,斐波那契查找的时间复杂度还是O(log2n),且其期望复杂度也为O(log2n),

但是与折半查找相比,斐波那契查找的优点是它只涉及加法和减法运算,而不用除法,

而除法比加减法要占用更多的时间,因此,斐波那契查找的运行时间理论上比折半查找小,

但是还是得视具体情况而定。

猜你喜欢

转载自www.cnblogs.com/zhoubo123/p/11258795.html