4

按照此处找到的答案https://stackoverflow.com/a/10931091/1311773,我正在尝试实现两个堆,以便计算运行中位数。

我对堆不熟悉,并且不确定从哪里开始实现这里描述的这个功能。http://programmingpraxis.com/2012/05/29/streaming-median/

我的目标是创建一个小型测试程序,可以有效地计算运行中位数,因此随着列表的增长,中位数不需要从头开始重新计算。使用两个堆,我应该能够做到,我只是不知道如何开始实施它。

对此的任何建议将不胜感激。

4

2 回答 2

4

std::priority_queue模板提供了堆的所有属性。恒定时间最大或最小提取(取决于项目的比较方式)和对数时间插入。它可以在<queue>头文件中找到。

默认情况下,priority_queue是一个最大堆。

int numbers[11] = { 0, 9, 3, 4, 8, 12, 2, 11, 10, 1, 5 };
std::priority_queue<int> myheap(numbers, numbers + 11);
std::cout << "biggest " << myheap.top() << std::endl; // 12
myheap.pop();
std::cout << "biggest " << myheap.top() << std::endl; // 11
myheap.push(6);
std::cout << "biggest " << myheap.top() << std::endl; // 11
myheap.push(13);
std::cout << "biggest " << myheap.top() << std::endl; // 13

以下是如何创建最小堆的示例:

std::priority_queue<
    int,
    std::priority_queue<int>::container_type,
    std::greater<int>
>;

要实现流式中位数算法,方法类似于:

  • 为小于中位数的项目创建一个最大堆
  • 为大于中位数的项目创建一个最小堆
  • 将新项目推入堆时
    • 决定应该将其推入哪个堆,然后将其推到那里
    • 如果其中一个堆的大小比另一个堆大 1 以上,则弹出较大的堆,然后将该元素放入较小的堆中

然后,中位数是较大堆的顶部,或者是两个堆顶部的平均值。

如果您觉得需要手动管理堆,C++请提供允许您在自己的随机访问数据结构上执行此操作的算法。

  • std::make_heap-- heapify 迭代器端点指定的区域
  • std::push_heap-- 假设前 N-1 个元素已经是一个堆,并将第 N 个元素合并到堆中
  • std::pop_heap -- 将区域中的第一个元素放在最后一个位置,并重新堆集该区域,但不理会最后一个元素
于 2012-06-10T04:30:07.070 回答
0

我想这会有所帮助。谢谢。

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include <vector>         
    #include <functional>

    typedef priority_queue<unsigned int> type_H_low;
    typedef priority_queue<unsigned int, std::vector<unsigned int>, std::greater<unsigned int> > type_H_high;

    size_t signum(int left, int right) {
        if (left == right){
            return 0;
        }
        return (left < right)?-1:1;
    }

    void get_median( unsigned int x_i, unsigned int &m, type_H_low *l, type_H_high *r) {

        switch (signum( l->size(), r->size() )) {
        case 1: // There are more elements in left (max) heap
            if (x_i < m) {
                r->push(l->top());
                l->pop();
                l->push(x_i);
            } else {
                r->push(x_i);
            }
            break;

        case 0: // The left and right heaps contain same number of elements
            if (x_i < m){
                l->push(x_i);
            } else {
                r->push(x_i);
            }
            break;

        case -1: // There are more elements in right (min) heap
            if (x_i < m){
                l->push(x_i);
            } else {
                l->push(r->top());
                r->pop();
                r->push(x_i);
            }
            break;
        }

        if (l->size() == r->size()){
            m = l->top();
        } else if (l->size() > r->size()){
            m = l->top();
        } else {
            m = r->top();
        }

        return;
    }

    void print_median(vector<unsigned int> v) {
        unsigned int median = 0;
        long int sum = 0;
        type_H_low  H_low;
        type_H_high H_high;

        for (vector<unsigned int>::iterator x_i = v.begin(); x_i != v.end(); x_i++) {
            get_median(*x_i, median, &H_low, &H_high);
            std::cout << median << std::endl;
        }
    }
于 2017-06-28T22:58:47.027 回答