【问题标题】:C++ Implementing Heap Median FunctionC++ 实现堆中值函数
【发布时间】:2012-06-13 13:02:08
【问题描述】:

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

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

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

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

【问题讨论】:

  • 堆是一种树还是向量数组?

标签: c++ heap median


【解决方案1】:

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 -- 堆积迭代器端点指定的区域
  • std::push_heap -- 假设前 N-1 个元素已经是一个堆,并将第 N 个元素合并到堆中
  • std::pop_heap -- 将区域中的第一个元素放在最后一个位置,并重新堆集该区域,但保留最后一个元素

【讨论】:

  • 我在代码上找不到任何资源来实现它。我对模板或者priority_queue的去向不是很了解。我知道它带有很多内置功能。
  • @Andrew:我提供了一些例子,希望对您有所帮助。
  • 这个算法的速度和成本,以及内存空间是多少?使用堆方法计算运行中位数是否比反复使用 Quickselect 之类的方法更快?
  • @Andrew:维基百科有一篇关于堆算法的好文章。
【解决方案2】:

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

    #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;
        }
    }

【讨论】:

  • 您已经将此exact same answer 发布到另一个问题。我建议只保留其中一个(可能是另一个,因为这是一个更受欢迎的问题),但如果您决定保留这个,请edit 它修复缩进并添加一些评论,因为我写在那里。谢谢!
猜你喜欢
  • 2021-03-18
  • 1970-01-01
  • 2013-11-19
  • 2014-09-01
  • 2010-12-15
  • 2020-08-27
  • 2010-11-27
  • 1970-01-01
  • 2010-11-26
相关资源
最近更新 更多