写在前面
不得不说,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也写出来的,可惜手残打字慢,我太难了……
之后再说吧……