有序向量:二分查找&斐波那契查找&插值查找

统一接口:

template <typename T>//查找算法统一接口,0<= lo < hi <= _size
Rnak vector<T>::search(T const & e,Rank lo,Rank hi) const{
    return (rand()%2)?//按1/2的概率随机选用算法
    binSearch(_elem, e, lo, hi);//二分查找算法
    :fibSearch(_elem, e, lo, ho);//斐波那契查找算法
}

A二分查找:

减而治之(二分(折半)策略)。将区间分为3部分:

     S[lo, mi)<=S[mi]<=S(mi, hi);

记x=S[mi].查找目标为e.
e < x :则e 在左侧区间S[lo, mi),通过递归深入查找。
e > x :则e 在右侧区间S(mi, hi),通过递归深入查找。
e = x :则e==x,返回值即可。
每次经过比较将问题规模至少减少一半(甚至直接找到)

时间复杂度是O(log 2 n )

template <typename T> 0<= lo <=hi <=user_size_t
static Rank binSearch(T* A, T const & e, Rank lo,Rank hi){
    while(lo < hi){
        Rank mi = (lo+hi)>>1;  //以中点划分区间
        if(e<A[mi]) hi=mi;  //深入左半区间查找
        else if(A[mi] <e) lo= mi+1;  //深入右半区间查找
        else return mi;  //mi处即是所找对象
    }
    return -1; //查找失败,在整个区间没找到对象e
}

A斐波那契查找:
斐波那契查找的时间复杂度还是O(log 2 n ),但与折半查找相比,斐波那契查找的优点是它只涉及加法和减法运算,而不用除法,理论上比折半查找小,但是还是得视具体情况而定。

template <typename T> 0<= lo <=hi <=user_size_t
static Rank fibSearch(T* A, T const & e, Rank lo,Rank hi){
    Fib fib(hi-lo);  //创建Fib数列
    while(lo <hi){
        while(hi-lo<fib.get()) fib.prev();
        Rank mi = lo +fib.get() -1; //按黄金比例切分
        if(e<A[mi]) hi=mi;  //深入左半区间查找
        else if(A[mi] <e) lo= mi+1;  //深入右半区间查找
        else return mi;  //mi处即是所找对象
    }
    return -1; //查找失败,在整个区间没找到对象e
}

B二分查找(改进):
mi同样是中心轴点,查找对象为e,x=S[mi]
如果e < x : 则深入查找[lo, mi)
如果e >=x: 则深入查找[mi,hi)

template <typename T> 0<= lo <=hi <=user_size_t
static Rank binSearch(T* A, T const & e, Rank lo,Rank hi){
    while(hi- lo > 1){ //区间缩小为1时停止
        while(hi-lo<fib.get()) fib.prev();
        Rank mi = (lo+hi)>>1;  //以中点划分区间
        e< A[mi]? hi= mi :lo= mi;
    }
    return A[lo]==e? lo : -1; //判断是否找到
}

A插值查找:
如果有序向量中各元素是均匀独立分布的,于是[lo, hi)中的元素大小大致成线性趋势增长。
于是我们通过秩的比大致等于值的比:
这里写图片描述
来猜测e的大致位置

mi=lo+(hi- lo)*[(e- A[lo]) / (A[hi]- A[lo])];

从而提高区间收敛的速度。

时间复杂度是O(loglog n)

template <typename T> 0<= lo <=hi <=user_size_t
static Rank binSearch(T* A, T const & e, Rank lo,Rank hi){
    Rank mi=lo+(hi- lo)*[(e- A[lo]) / (A[hi]- A[lo])];
    while(mi>=lo){  //mi<lo时停止
        if(e==A[mi]) return mi;
        else if(e>A[mi])
            lo=mi+1;
        else
            hi=mi;
        Rank mi=lo+(hi- lo)*[(e- A[lo]) / (A[hi]- A[lo])];
    }
    return -1; //查找失败
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值