C++ 数据结构学习 ---- 中位数算法

1 头文件

1.1 vector函数

C++ 数据结构学习 ---- 向量_孤城寻欢的博客-CSDN博客

2 相关算法

2.1 暴力算法

// 中位数算法蛮力版:效率低,仅适用于max(n1, n2)较小的情况
//子向量S1[lo1, lo1 + n1)和S2[lo2, lo2 + n2)分别有序,数据项可能重复
template <typename T> T trivialMedian(Vector<T>& S1, int lo1, int n1, Vector<T>& S2, int lo2, int n2) {

    cout<<endl << "平凡中位数" ;  //printf("trivial median\n");
    int hi1 = lo1 + n1, hi2 = lo2 + n2;
    Vector<T> S; //将两个有序子向量归并为一个有序向量
    while ((lo1 < hi1) && (lo2 < hi2))
        S.insert(S1[lo1] <= S2[lo2] ? S1[lo1++] : S2[lo2++]);
    while (lo1 < hi1) S.insert(S1[lo1++]);
    while (lo2 < hi2) S.insert(S2[lo2++]);
    //print(S);
    return S[(n1 + n2) / 2]; //直接返回归并向量的中位数
}

2.2 低效版中位数算法

//中位数算法(低效版)
//向量S1[lo1, lo1 + n1)和S2[lo2, lo2 + n2)分别有序,数据项可能重复
template <typename T> T median(Vector<T>& S1, int lo1, int n1, Vector<T>& S2, int lo2, int n2) { 
    if (n1 > n2) return median(S2, lo2, n2, S1, lo1, n1); //确保n1 <= n2
    for (int i = 0; i < lo1; i++)cout << "     .";// printf("    .");
   for (int i = 0; i < n1; i++)
       cout << S1[lo1 + i] <<" ";// print(S1[lo1 + i]);
   cout << endl;
 for (int i = lo1 + n1; i < S1.size(); i++)
     cout << "     ."<< endl;// printf("    ."); printf("\n");
   for (int i = 0; i < lo2; i++) cout << "     ."; //printf("    .");
   for (int i = 0; i < n2; i++) cout << S2[lo2 + i] << " ";//print(S2[lo2 + i]); 
   cout << endl;
   for (int i = lo2 + n2; i < S2.size(); i++) cout << "     ."<<endl<<endl; //printf("    .");  printf("\n--\n");
    if (n2 < 6) //递归基:1 <= n1 <= n2 <= 5
       return trivialMedian(S1, lo1, n1, S2, lo2, n2);
    ///
    //                lo1            lo1 + n1/2      lo1 + n1 - 1
    //                 |                 |                 |
    //                 X >>>>>>>>>>>>>>> X >>>>>>>>>>>>>>> X
    // Y .. trimmed .. Y >>>>>>>>>>>>>>> Y >>>>>>>>>>>>>>> Y .. trimmed .. Y
    // |               |                 |                 |               |
    // lo2     lo2 + (n2-n1)/2       lo2 + n2/2     lo2 + (n2+n1)/2    lo2 + n2 -1
    ///
    if (2 * n1 < n2) //若两个向量的长度相差悬殊,则长者(S2)的两翼可直接截除
        return median(S1, lo1, n1, S2, lo2 + (n2 - n1 - 1) / 2, n1 + 2 - (n2 - n1) % 2);
    ///
    //    lo1                  lo1 + n1/2              lo1 + n1 - 1
    //     |                       |                       |
    //     X >>>>>>>>>>>>>>>>>>>>> X >>>>>>>>>>>>>>>>>>>>> X
    //                             |
    //                            m1
    ///
    //                            mi2b
    //                             |
    // lo2 + n2 - 1         lo2 + n2 - 1 - n1/2
    //     |                       |
    //     Y <<<<<<<<<<<<<<<<<<<<< Y ...
    //                                .
    //                               .
    //                              .
    //                             .
    //                            .
    //                           .
    //                          .
    //                         ... Y <<<<<<<<<<<<<<<<<<<<< Y
    //                             |                       |
    //                       lo2 + (n1-1)/2               lo2
    //                             |
    //                            mi2a
    ///
    int mi1 = lo1 + n1 / 2;
    int mi2a = lo2 + (n1 - 1) / 2;
    int mi2b = lo2 + n2 - 1 - n1 / 2;
    if (S1[mi1] > S2[mi2b]) //取S1左半、S2右半
        return median(S1, lo1, n1 / 2 + 1, S2, mi2a, n2 - (n1 - 1) / 2);
    else if (S1[mi1] < S2[mi2a]) //取S1右半、S2左半
        return median(S1, mi1, (n1 + 1) / 2, S2, lo2, n2 - n1 / 2);
    else //S1保留,S2左右同时缩短
        return median(S1, lo1, n1, S2, mi2a, n2 - (n1 - 1) / 2 * 2);
}

2.3 高效版中位数算法

//序列S1[lo1, lo1 + n)和S2[lo2, lo2 + n)分别有序,n > 0,数据项可能重复
//中位数算法(高效版)
template <typename T> T median(Vector<T>& S1, int lo1, Vector<T>& S2, int lo2, int n) {

    cout << "中位数" << endl;// printf("median\n");
    for (int i = 0; i < lo1; i++)
        cout << "     .";//printf("     ."); 
    for (int i = 0; i < n; i++)
        cout << S1[lo1 + i] << " ";// print(S1[lo1 + i]);
    cout << endl;
    for (int i = lo1 + n; i < S1.size(); i++)
        cout << "     ." << endl;// printf("    ."); printf("\n");
    for (int i = 0; i < lo2; i++)
        cout << "     .";// printf("    .");
    for (int i = 0; i < n; i++)
        cout << S2[lo2 + i] << " ";//print(S2[lo2 + i]); 
    cout << endl;
    for (int i = lo2 + n; i < S2.size(); i++)
        cout << "     ." << endl << endl; //printf("    .");  printf("\n--\n");
    if (n < 3) return trivialMedian(S1, lo1, n, S2, lo2, n); //递归基
    int mi1 = lo1 + n / 2, mi2 = lo2 + (n - 1) / 2; //长度(接近)减半
    if (S1[mi1] < S2[mi2])
        return median(S1, mi1, S2, lo2, n + lo1 - mi1); //取S1右半、S2左半
    else if (S1[mi1] > S2[mi2])
        return median(S1, lo1, S2, mi2, n + lo2 - mi2); //取S1左半、S2右半
    else
        return S1[mi1];
}

3 完整代码

//生成长度为n的随机有序向量,元素取值来自[min, max]
Vector<int> randomSortedVector(int n, int min, int max) { //ACP, Vol.2, Algorithm S
    cout << "创造一个长度为" << n << "的任意有序向量!" << endl; //  printf("creating a random sorted vector of size %d...\n", n);
    Vector<int> A;
    for (int i = min; i <= max; i++)
        if (rand() % (max - i + 1) < n)
        {
            cout << i << " ";
            A.insert(i); n--;
        }
    cout << endl;
    return A;
}


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include "Median.h"

using namespace std;



int main() {
    int nTest = 1; //测试轮数
    int n = 8; //向量长度
    int min1 = 0, max1 =100; //数值范围
    int min2 =2, max2 = 9; //数值范围
    if ((nTest < 1) || (n < 1) || (max1 + 1 < min1 + n) || (max2 + 1 < min2 + n))
    {
        cout << "错误!" << endl; //printf("arguments error\a\a\n");
        return -1;
     
    }
    // 随机种子
    srand((unsigned int)time(NULL));
   
    // 每次测试100组
    for (int i = 0; i < nTest; i++) {
        // 随机生成向量
        Vector<int> A1 = randomSortedVector(n, min1, max1);// print(A1);
        Vector<int> A2 = randomSortedVector(n, min2, max2); //print(A2);
        // 计算中位数,并与蛮力算法(更不易出错)的结果对比
        int m1 = median(A1, 0, A2, 0, n);
        int m2 = trivialMedian(A1, 0, n, A2, 0, n);
        if (m1 == m2) {
            cout << endl << "中位数:" << m1 << "=" << m2 << endl << endl;// printf("\nmedian: %d = %d\a\n\n\n", m1, m2); 
        }
        else {
            cout << "错误!" << endl << endl;
            // printf("\nmedian: %d <Error> %d\a\a\n\n\n", m1, m2); 
            getchar();
        }
    }

    int n1 = 10; //向量1长度、取值范围
    int n2 = 8; //向量2长度、取值范围

    for (int i = 0; i < nTest; i++) {
        // 随机生成向量
        Vector<int> A1 = randomSortedVector(n1, min1, max1);
        Vector<int> A2 = randomSortedVector(n2, min2, max2); cout << endl;// printf("--\n");
        // 计算中位数,并与蛮力算法(更不易出错)的结果对比
        int m1 = median(A1, 0, n1, A2, 0, n2);
        int m2 = trivialMedian(A1, 0, n1, A2, 0, n2);
        if (m1 == m2) {
            cout << endl << "中位数:" << m1 << "=" << m2 << endl << endl;// printf("\nmedian: %d = %d\a\n\n\n", m1, m2); 
        }
        else {
            cout << "错误!" << endl << endl;
            // printf("\nmedian: %d <Error> %d\a\a\n\n\n", m1, m2); 
            getchar();
        }
    }

	system("pause");
	return 0;// 返回
}

4 运行结果及截图

猜你喜欢

转载自blog.csdn.net/qq_58240448/article/details/128116519