算法第二章上机实践报告
1.实验题目:7-3 两个有序序列的中位数
2.问题描述:已知有两个等长的非降序序列S1, S2, 求S1与S2合并后的中位数。(要求:使用时间复杂度T(n) =O(log n)的算法。)
3.算法描述:(1)比较两个等长的非降序序列的中间量的大小,然后取大数的左段,小数的右段,如果相等则可直接返回该数;
注意:为保证每次折半时,折出来的两个非降序序列为登场序列——在计算第二组序列的中间值时需先 + 1,再 / 2;
这样可使数组长度为偶数时,中间数的位置前后相差1,而奇数则不造成影响;
(2)不断进行折半操作直到最后只剩下4个数或2个数时,进行下列处理方式:
a.当剩下4个数时,将无法继续进行递归,可直接返回第二小的数
b.当剩下2个数时,,可直接进行比较,然后直接返回其中较小的数
4.算法代码:
int BinarySearch(int aleft,int aright,int bleft,int bright){ // (2)-b if((aleft == aright) && (bleft == bright)){ return min(a[aleft],b[bleft]); } // (2)-a if((aleft + 1 == aright) && (bleft +1 == bright)){ if(a[aleft] == b[bleft]) return a[aleft]; else if(a[aleft] < b[bleft]) aleft++; else bleft++; return min(a[aleft],b[bleft]); } // (1)-注意 int amid = (aleft + aright) / 2; int bmid = (bleft + bright + 1) / 2; // (1) if(a[amid] == b[bmid]) return a[amid]; else if(a[amid] < b[bmid]){ return BinarySearch(amid,aright,bleft,bmid); } else return BinarySearch(aleft,amid,bmid,bright); }
5.时间复杂度:由于这是由两个长度都为n的数组组成的,我们可以先假设 m = 2 * n ;
两个数组的中间量每对比一次,搜索范围——两个数组就会各折一半,直到找到两数组合并后的中位数;
最好情况下算法的时间复杂度T(n) = O(1),,最开始时两数组的中间数就相同,可直接得出合并后的中位数。
最坏情况是两个数组都比到最后只剩下2个或4个数,才最终找到合并后的中位数,则T(m) = T(m/2) + O(1);
因为m^d = 1 = m^0,所以d = 0,又因为logb a = log2 1 = 0,所以d = logb a;
所以最坏情况下算法的时间复杂度T(m) = O(m^d*log m) = O(log m),所以T(n) = O(log n);
6.空间复杂度:在算法,除了需要用到2*n个空间用于存储两个非降序序列的数组,仅需6个空间用于存储辅助变量,所以空间复杂度为O(1).
7.心得体会:这次是我和我搭档一起配合完成的3道上机题,刚开始我们非常顺利的就完成所有题目,直到被老师检查后,老师提出了7-3要这道题使用时间复杂度为log n的算法。
刚开始针对这道题的新解法时,我们脑子里只有一个大致的想法,就是使用二分法。但如何使用二分法还十分得不确定,但在经过了一系列的讨论之后,我们想出了大致的解决方法,但当我们开始真实敲代码时,问题又来了!如何才能确保每次折半后的两个数组是等长的呢?
我们俩针对这个问题想了好久,也尝试着打了些代码,但最后都宣告失败,直到最后下课后,我们可其他组讨论起了这道题也上网找了一些别人的代码,才终于搞懂了这个问题的解决方法。
从这次合作中,我深刻体会到:比起一个人在那静静地思考,多个人一起思考时更能产生强烈的思维火花。