二分法的改进方法(C++)(Fibonacci Search)

一、二分法的引入

1.背景

要求:
在一个有序向量中查找一个目标元素值,找到返回下标,反之返回-1。
直观思路:
挨个对比,时间复杂度为o(n)。
但是相对于下面的算法,其复杂度的差距还是让我们难以忍受的。

2.思路

对于直观思路的这种算法,在无序向量下通常也适用。然而对于有序这个条件来说,我们往往可以采用“减而治之”,通过从对半比较,将问题的规模每次缩小一半,可以大大减少时间复杂度。

3.实现(主要设计思路)

template<typename 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;//深入前半段[lo,mi)继续查找
         else if(A[mi]<e)
         lo=mi+1;//深入后半段(mi,hi)
         else
         return mi;//在mi处命中
    }
    return -1;//查找失败
}    
         

4.复杂度分析

在这里插入图片描述

由于问题是在规模为n的向量中查找目标元素,而二分法每次在操作时都会将问题规模缩小1/2。所以复杂度的底层表示一定为对数。
通过上图来看,(成功查找)前三列的总查找次数为2+3+4+4+5+5+6=29次,共有7情况,大致平均为29/7=4.14。而最坏的情况为查找了3+4+4+5+4+5+5+6=36次,共有8种情况,大致平均为36/8=4.5=1.50*log28(以2为底8的对数)。复杂度大致为O(1.5logn)。

二、利用斐波那契数改进

1.思路及原理

通过观察不难发现,在生成左右分支时,进入左或者右分支的比较次数不相等(即往左需要进行一次比较而往右需要进行两次),但是递归深度却相同。
思路:通过递归深度的不均衡,对转向成本的不均衡进行补偿
比如,若设n=fib(k)-1(便于研究计算),则可取mi=fib(k-1)-1。
所以,分完后前后向量的长度分别为fib(k-1)-1fib(k-2)-1

2.查找长度

在这里插入图片描述
n的规模仍沿用上述例子即7=n=fib(6-1):
平均成功查找长度=(5+4+3+5+2+5+4)/7=28/7=4.00<4.14
平均失败查找长度=(4+5+4+4+5+4+5+4)/8=35/8=4.38<4.50

3.优越性的严格证明

因为左方向深入与右方向深入所花费的时间不同,因此我们只需要选取A[xn]作为分开的轴点,当然0<=x<1。
比如:二分查找对应于x=0.5,Fibonacci查找对应于x=0.6180339…(黄金分割比)
相信聪明的大家早已在心中就有了答案
设平均查找长度为f(x)*log2n(以2为底n的对数)
即f(x)log2n=x[1+f(x)*log2n(以2为底n的对数))]+(1-x)*2+f(x)*log2((1-x)n)](以2为底(1-x)n的对数)***(上面的+1和+2对应每次向左或者向右的查找操作时间 由于本菜鸟打不出来拉姆他(n前面的系数)就将其替换为x)
聪明的大家在经过简单运用高数知识后可整理为以下式子
-ln2/f(x)=xlnx+(1-x)ln(1-x)/(2-x)
当x=0.6180339…(黄金分割比)时,f(x)=1.440420…达到最小
在这里插入图片描述

4.实现

template<typename T>//0<=lo<=hi<=_size
static Rank fibSearch(T*A,T const&e,Rank lo,Rank hi)
{
    Fib fib(hi-lo);//用O(logxn)=O(logx(hi-lo))时间创建Fib数列(x为黄金分割比且表示底数)
    while(lo<hi)//每部迭代可能要做两次比较判断,有三个分支
    {    
         while(hi-lo<fib.get())fib.prev();//通过向前顺序查找,确定形如Fib(k)-1的轴点(分摊O(1))
         Rank mi=lo+fib.get()-1;//按黄金比例切分
         if(e<A[mi])
         hi=mi;//深入前半段[lo,mi)继续查找
         else if(A[mi]<e)
         lo=mi+1;//深入后半段(mi,hi)
         else
         return mi;//在mi处命中
    }
    return -1;//查找失败
}

三、总结

相信聪明的各位已经不费吹灰之力搞懂了此次算法的逻辑与实现。在大体二分查找基础框架不变的情况下,通过改变常系数使得我们的算法整体达到了优化,这就是FibonacciSearch主要的优越之处和魅力所在。
以上就是本次二分查找改进的步骤,主要参考《邓俊辉 数据结构》讲义和自己的一些理解完成,像是一次课后总结。由于本菜鸟是第一次写csdn,有哪些不恰当或者不对的地方,欢迎提出宝贵的建议,本菜鸟会及时改正。

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值