【数据结构课程设计】计算动态中位数

一、问题描述:

1、给定一系列数据,如果按大小排序,则中位数只是中间项(数据个数为奇数),或者

如果没有中间项(数据个数为偶数),则为两个中间项的平均值。 例如,序列 3, 1,

9, 25, 12 的中位数是 9 ,而序列 8, 4, 11, 18 的中位数是 9.5

2、如果增加数据,则需要能够动态维护运行中位数。即当遇到每个新数据时,都会计

算更新的中位数。 当然,这应该尽可能高效地完成。

3、例如,依次读入数据 3, 1, 9, 25, 12,则动态返回的中位数列表应该是 3, 2.0, 3, 6.0, 9

二、需求分析:

1. 首先设计一个计算动态中位数的初始算法版本,可以每次读入新数据时,及时排序

并更新当前中位数;

2. 设计计算动态中位数的高效优化算法版本,可借助于堆(heap)实现,并分析算法的

时间复杂度;

3. 对于高效优化版本,测试数据规模为对 10 万个随机数据计算中位数,统计运行时间

(单位:秒)

三、模块设计:

根据具体需求设计以下三个主要的模块:

(1)初始算法模块:初始算法的实现通过数组存储数据,进行插入排序,寻找中位数通过数组个数分类判断下标。

(2)高效优化版本模块:借助heap实现,利用大顶堆存小数,小顶堆存大数,利用堆插入保持大顶堆中的元素个数与小顶堆元素个数的相对平衡,寻找中位数可以直接取堆顶元素。

(3)对比测试模块:通过随机种子srand((unsigned int)time(0)) 生成随机数,计算高效版本和初始版本各自的执行时间,进行对比显示。对比测试设置两个函数分别测试两个版本的执行时间,可设置参数N为测试数据量的大小。

四、详细设计:

1、存储结构:

vector<double>v;//存放数据的数组

priority_queue<double>down;//大顶堆,存较小的一半

priority_queue<double,vector<double>,greater<double>> up;//小顶堆

2、主要算法设计:

(1)初始算法,插入x到数组并排序

void mysort(double x) {       
    v.push_back(x);
    int n = v.size()-1;//之前的元素个数
    if (n == 0)return;
    int t=n+1;//从t号下标开始后移
    for (int i = n - 1; i >= 0; --i) {//遍历找到x应当插入的位置
        if (v[i] >= x) { t = i ; }
    }
    if (t == n+1)return;//已经有序
    for (int i = n - 1; i >= t; --i) {//后移
        v[i+1] = v[i];
    }
    v[t] = x;
}
double findm() {//寻找中位数(初始算法)
    int n = v.size();
    if (n % 2) {
        return v[n / 2];
    }
    else {
        double pj = (v[n / 2] + v[n / 2 - 1]) / 2; 
        return pj;
    }
}

(2)高效算法,堆插入

void heapsort(double x) {
    if (down.empty() || x <= down.top())down.push(x);
    else up.push(x);
    //调整 
    if (down.size() >= up.size() + 2) { up.push(down.top()); down.pop(); }
    if (up.size() >= down.size() + 1){down.push(up.top()); up.pop();}
    //始终保持down中个数=up/up+1
    return;
}
void findheapm() { //寻找两堆的中位数
    int num = down.size() + up.size();
    if (num % 2)cout << "此时中位数为" << down.top() << endl;
    else cout << "此时中位数为" << (down.top() + up.top()) / 2 << endl;
    return;
}

(3)对比测试函数

void ff(int N) {//测试数据量N的堆算法
    srand((unsigned int)time(0));//随机种子
    clock_t start, end; double timee;//开始时间 结束时间 时间间隔
    start = clock();
    for (int i = 0; i < N; i++)heapsort(rand() % N);//生成随机数
    end = clock();
    timee = (double)(end - start) / CLOCKS_PER_SEC;//转化成秒
    cout << "高效版本执行时间为:" << timee <<"s" << endl;
}
void ff1() {//测试初始算法
    srand((unsigned int)time(0));//随机种子
    clock_t start, end; double timee;//开始时间 结束时间 时间间隔
    start = clock();
    for (int i = 0; i < 10000; i++)mysort(rand() % 10000);//生成随机数
    end = clock();
    timee = (double)(end - start) / CLOCKS_PER_SEC;//转化成秒
    cout << "初始版本执行时间为:" << timee << "s" << endl;
}

五、测试结果:

1) 测试用例设计:

初始版本输入3、1、2、3,返回动态中位数应为3、2、2、2.5;高效版本输入2、1、4、

7,返回动态中位数应为2、1.5、2、3。接下来两个测试功能:第一个测试初始版本和高效

版本数据规模为1万的用时结果,第二个单独测试高效版本对10万数据的用时。

2) 测试结果如下

感谢观看 欢迎交流讨论!!!

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吗喽的命也是命吗喽的命

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值