算法第二章上机实践报告

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的算法。

      刚开始针对这道题的新解法时,我们脑子里只有一个大致的想法,就是使用二分法。但如何使用二分法还十分得不确定,但在经过了一系列的讨论之后,我们想出了大致的解决方法,但当我们开始真实敲代码时,问题又来了!如何才能确保每次折半后的两个数组是等长的呢?

      我们俩针对这个问题想了好久,也尝试着打了些代码,但最后都宣告失败,直到最后下课后,我们可其他组讨论起了这道题也上网找了一些别人的代码,才终于搞懂了这个问题的解决方法。

      从这次合作中,我深刻体会到:比起一个人在那静静地思考,多个人一起思考时更能产生强烈的思维火花。

posted @ 2018-10-21 01:38  cc-wanna  阅读(130)  评论(0编辑  收藏  举报