数据结构之二分查找

写在前面

不得不说,b站真是个学习的好地方。然后,突发奇想的来这写写自己的笔记……
不会怎么使用这个网站,哎哎哎哎哎……
然后,今天学习了清华老师邓俊辉的MOOC数据结构与算法(羡慕清华学生有个好老师)。
y1s1,老师讲的是真的细致,字也是秀的飞起,这要练多久,时间不长的话我也想练练呢。
好吧,进入正题……

二分查找

binSearch

不多说,献上代码

static Rank binSearch (T* A,T const& e,Rank lo,Rank hi){
	while(lo<hi){//每步迭代可能要做两次比较判断,有三个分支 
		Rank mi=(lo+hi)/2;//以中点为轴 
		if(e<a[mi])hi=mi;//深入前半段 
		else if(a[mi]<e)lo=mi+1;//深入后半段
		else return mi; //在mid命中
	}
	return -1;//查找失败	
}

嗯,为什么我不太喜欢这代码颜色风格呢,明明别人的都是很好看的……哎哎哎哎哎
然后,为了做杭电oj的2019这道题,我魔改了一下。

#include<stdio.h>
int search(int a[],int e,int lo,int hi){
	//int lo=0,hi=n-1;
	while(lo<hi){
		int mi=(lo+hi)/2;//以中点为轴 
		if(e<a[mi])hi=mi;//深入前半段 
		else if(e>a[lo])lo=mi+1;//深入后半段
		else return mi; //在mid命中
	}
	return lo;//查找失败	
}
int main()
{
	int n,m,a[10001],i,x;
	while (true){
		scanf("%d%d",&n,&m);
		if(n==0&&m==0)break;
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		x=search(a,m,0,n);
		for(i=n;i>x;i--){
			a[i]=a[i-1];
		}
		a[x]=m;
		for(i=0;i<n;i++)
			printf("%d ",a[i]);
		printf("%d\n",a[i]);	 
	}
	 return 0;
} 

主要看前面哪一部分,emmm,就是把查找失败的返回值换成了lo的值,也就是插入位置
算法时间效率大概是O(1.5logn)
老实说这就很符合我的要求了,不过老师说这不够好,还有更好的……

fibSearch

献上代码,哎哎哎哎哎,手残党打代码太太太痛苦了。

static Rank fibSearch(T* A,T const& e,Rank lo,Rank hi){
	Fib fib(hi-lo);//用O(log(hi-lo)) 时间创建Fib数列
	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;//查找失败 
} 

emmm,按照我自己的理解,这个代码大体解决了进入前半段和后半段比较次数的不同,让比较向前半段偏移,效率大概为O(1.44logn),提高了一些。也不知道我理解的对不对,ε=(´ο`*)))唉。

binSearch版本B

献上代码

static Rank binSearch(T* A,T const& e,Rank lo,Rank hi){
	while (1<hi-lo){//有效找区间的宽度缩短至1时,算法才会终止 
		Rank mi=(hi+lo)>>1;//以中心为轴点,经比较后确定深入 
		(e<A[mi])?hi=mi:lo=mi;//[lo,mi)或[mi,hi) 
	}//出口时hi=lo+1,查找区间仅包含一个元素A[lo] 
	return (e==A[mi])?lo:-1;//返回命中元素或-1 
} 

不得不在说一下,邓俊辉老师教的是真的好。
emmm,这个算法,嗯,为啥代码前面没有行数显示……
就简单说一下吧。
改进了算法左右两侧深入比较次数不平衡的地方,fibSearch是通过数学计算得出最优的轴点进行深入,这确实直接用一次比较解决问题。 最终使得lo和hi区间等于一,在lo命中或返回-1.

binSearch版本C

献上代码

static Rank binSearch(T* A,T const& e,Rank lo,Rank hi){
	while (hi<lo){//不变性:A[0,lo)<=e<A[hi,n) 
		Rank mi=(hi+lo)>>1;//以中心为轴点,经比较后确定深入 
		(e<A[mi])?hi=mi:lo=mi+1;//[lo,mi)或(mi,hi) 
	}//出口时,A[lo=hi]为大于e的最小元素 
	return lo--;//故lo-1即不大于e的元素的最大秩 
} 

这个算法稍微改进了一下,在binSearch版本B解决左右两侧深入比较次数不同的基础上能返回不大于e的元素的最大的秩,方便元素的插入
emmm,虽然还想不太明白lo=mi+1什么时候要加1,不加会怎么样
哎哎哎,感觉智商不太够了。啥时候用程序调试调试,看看是怎么样的。

写在最后

emm……
总结一下,
fibSearch太难了,我选择死亡。
嗯,还是普普通通的binSearch适合我。
这是邓老师讲解的版本A,本来还想把邓老师后来讲的版本B也写出来的,可惜手残打字慢,我太难了……
之后再说吧……

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值