算法第二章上机实践报告

Posted ljl-gd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法第二章上机实践报告相关的知识,希望对你有一定的参考价值。

1、 实践题目:7-3 两个有序序列的中位数(二分法解法)

2、 问题描述:对于两个等长的非降序序列S1S2,如何利用二分法的思想求出S1S2并集的中位数,要求算法的时间复杂度为T(logn)

3、 算法描述:总体思想:采用分治与递归策略,二分法每次将问题规模减半(约减半),然后对问题进行递归处理,在进行递归的过程中对可能出现特殊的情况,就特殊安排处理。

(1) 解法一:

① 先排除两个两个等长序列的元素个数(奇和偶)的影响,首先对两个序列求中位数,求中位数的方法是如下,此方法为保证偶数序列的分割保持割后对称性,而对奇数序列不产生影响,如此可以保证递归的时候子问题也是两个等长的序列。

② 在两端标志还未出现相等或未出现其他特殊情况时,每次求得两个序列的中位数(如果序列是偶序列,则第二个序列的中位数定为A[(N-1) /2 + 1],即中位数的后一个数),将两个中位数进行比较,若两数相等的话,则可确认为此数为所求中位数。若不相等,则对两个数中较大的数的那一序列进行减掉比这个数大的(即这个数后面)的部分,保留其他;对另一个序列(较小数所在序列)而言,则减掉比它小的(即前面的)部分,保留其他,比较后,对剩下的等长序列进行递归调用。

③ 在进行递归过程中,若还未出现相等中位数,两序列的两端标志将会不断靠近,所以此时对于实例不同的序列,就会可能出现一些特殊情况,所以下面就讲解对于所有可能出现特殊情况的解决办法,第一种情况是当两序列都只剩最后一个时,就对两数进行比较,小的为所求中位数。

④ 第二种情况为两序列都最后只剩两个数而无法再进行递归下去(陷入死循环)时,第一个序列求中位数方法不变,第二个序列变为与第一序列相同的方法求得中位数,在这样的处理下再进行递归一次,所以之后两个共剩下三个数,就分两种情况,第一种为第一个序列剩一个,第二种为第二个序列剩一个,两种情况的解决方案都为:然后把剩一个的那组的数与剩两个那组的较大的数(也就是第二个数)进行比较,取小的那个数,那个数就是我们所求中位数。

⑤ 代码如下:

#include <iostream>
using namespace std;

int MidSearch(int a[], int b[], int la, int ra, int lb, int rb){
    int ma = (la + ra) / 2;
    int mb = (lb + rb + 1) / 2;
    
    if (la == ra && lb != rb){
        if (a[la] > b[rb])
            return b[rb];
        else 
            return a[la];
    }
    if (lb == rb && la != ra){
        if (b[lb] > a[ra])
            return a[ra];
        else 
            return b[lb];
    }
    if (la == ra && lb == rb){
        if (a[la] > b[lb])
            return b[lb];
        else 
            return a[la];
    }
    else{
        if (la == ra - 1 && lb == rb -1){
            ma = (la + ra) / 2;
            mb = (lb + rb) / 2;
        }
        if (a[ma] == b[mb]){
            return a[ma];
        }
        else if (a[ma] > b[mb]){
            MidSearch(a, b, la, ma, mb, rb);
        }
        else {
            MidSearch(a, b, ma, ra, lb, mb);
        }
    }
}

int a[100005], b[100005];
int main(){
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
        
    for (int j = 0; j < n; j++)
        cin >> b[j];
        
    cout << MidSearch(a, b, 0, n - 1, 0, n - 1) << endl;
    
    return 0;
}

(2) 解法二:

① 如果中位数在数组a中,那么若a[m]<b[n-m-2],此时比a[m]小的数最多只有n-2个,即a[m]不可能为第n小数,偏小更新左界;a[m]> b [n-m-1],此时比a[m]小的数至少有n个,a[m]不可能为第n小数,偏大更新右界;a[m]介于b[n-m-2]b [n-m-1]a[m]恰好为第n小数。 中位数在数组b中的情况类似。

② 代码如下:

#include <iostream>
using namespace std;
int a[1005], b[1005];

int mid_num(int a[], int b[], int n){
    int l = 0, r = n - 1;
    int m, tmp;
    while (l <= r){
        m = (l + r) / 2;
        tmp = (a[m] < b[n - m - 2]? b[n - m - 2]: a[m]);
        
        if (tmp > b[n - m -1])
            r = m - 1;
        else if (tmp > a[m + 1])
            l = m + 1;
        else return tmp;
    }
}

int main(){
    int n;
    cin >> n;
    for (int i = 0; i < n; i++){
        cin >> a[i];
    }
    for (int j = 0; j < n; j++){
        cin >> b[j];
    }
    cout << mid_num(a, b, n) << endl; 
    return 0;
} 

4、 算法时间及空间复杂度分析(含分析过程)

(1) 时间复杂度:

① 法一:

n = m / 2, T(m) = T(m / 2) + O(1)

因为:T(n) = αT(n / b) + O(nd)

所以:d = 0,  logba = d

得:T(m) = O(logm) = O(logn)

② 法二:

n = m / 2, T(m) = T(m / 2) + O(1)

因为:T(n) = αT(n / b) + O(nd)

所以:d = 0,  logba = d

得:T(m) = O(logm) = O(logn)

(2) 空间复杂度:

① 法一:O(n)

② 法二:O(n)

5、 心得体会(对本次实践的收获及疑惑的总结)

(1) 三道实践题来说:上课认真听讲,下课基本可以完成。

(2) 组队实践而言:在计算实践复杂度的时候可以校队一下结果,在设计算法、函数的时候可以交流一下方向。

(3) 第三题的难度提升体会:课后练习尽量用到新学的知识完成,做到学以致用;一个看似简单的问题其实多动动脑筋就会变得十分有趣。

6、 参考链接:

https://blog.csdn.net/bensonrachel/article/details/78157103

https://blog.csdn.net/yangliuy/article/details/7194199

以上是关于算法第二章上机实践报告的主要内容,如果未能解决你的问题,请参考以下文章

算法第二章上机实践报告

算法第二章上机实践报告

算法第二章上机实践报告

算法第二章上机实践报告

实践算法第二章上机实践报告

算法第二章上机实践报告