【问题标题】:High performance heap sorting高性能堆排序
【发布时间】:2014-03-10 18:59:18
【问题描述】:

我有一个大小超过500万的向量,每次我想从向量中取出一个键最小的元素,并对这个元素做一些处理。然而,随着这个特定元素的处理,向量中的所有剩余元素也将受到影响,以便它们的键更新。所以下次如果我想从向量中取出键最小的元素,我必须再次对向量进行排序。问题是从向量中拾取最小元素的次数会高达50万,所以程序运行的很慢。为了让大家更清楚的理解,我可以写如下代码来说明:

void function(vector<MyObj*>& A)
{ //A.size() is near 5 million, maybe even more such as 50 million.
    make_heap(A.begin(), A.end(), compare); // compare function is self-defined.
    for (int i=0; i<500000; i++)
    {
        MyObj* smallest_elem = A.front();
        pop_heap(A.begin(), A.end());
        A.pop_back();
        Process_MyObj(smallest_elem); // here all of the elements 
                                      // in A will be affect, causing 
                                      // their keys changed.

        make_heap(A.begin(), A.end()); // Since all elements' keys in A changed,
                                       // so heap sorting A once again is 
                                       // necessary in my viewpoint.
    }
}

有没有办法让代码尽可能高效地运行?欢迎任何想法,而不是对算法的有限改进,例如并行或其他任何东西。非常感谢!

【问题讨论】:

  • 处理如何影响所有其他元素是否有任何模式?真的是全部(在这种情况下,您的下限显然是 O(N))还是只是一些?可以同时增加和减少吗?

标签: c++ performance sorting parallel-processing binary-heap


【解决方案1】:

如果 Process_MyObj 确实影响了 A 中所有元素的键,我认为您无能为力。如果它只修改了一些键,你可以编写代码来更新堆中的单个元素。

由于您的代码现在是我看不到您从构建堆中获得了什么。我只需进行线性扫描以找到最小元素,将其与最后一个交换,然后弹出最后一个元素。

【讨论】:

  • 是的 - 线性扫描是 O(N),因此比 O(N log N) 的排序要好。
  • @user515430 同意。建立堆似乎没用。我这样做只是因为它来自一篇著名的论文,这也让我感到困惑。
【解决方案2】:

您可以尝试对向量进行排序并按顺序选择元素,而不是使用堆。

它不会提高 big-o 复杂度,但它可能会提高常数因子。

【讨论】:

    【解决方案3】:

    有多少时间在Process_MyObj,有多少时间在堆操作—— 50 / 50 %, 80 / 20 % ?
    这很重要,因为您想平衡两者。 考虑以下一般设置:

    Make a Todo list
    Loop:
        work on items ...
        update the Todo list
    

    太多时间更新列表意味着没有足够的时间做实际工作。 所以首先测量比率进程/堆时间。
    一种便宜的方法是使用 Process_MyObjcompare 完成了两次,例如

     P + H = 1.0 sec
    2P + H = 1.7 sec
    => P = .7, H = .3: P / H = 70 % / 30 %.
    


    make_heap 以线性时间运行 -- 见how-can-stdmake-heap-be-implemented-while-making-at-most-3n-comparisons—— 所以加速会有困难。 如果值是恒定的,则堆 64 位 将比指针更高效缓存。

    whats-new-in-purely-functional-data-structures-since-okasaki 在 cstheory.stack 上列出了几十篇论文,大部分是理论的, 但一两个可能与您的问题有关。

    真正的加速几乎总是针对特定问题,而不是一般性的。 你能告诉我们更多关于真正的问题吗?


    补充:如果大多数流行音乐都很小,而且推得很大, 尝试在大排序列表前面放置一个小缓存堆。伪代码:
    push:
        push( cacheheap )
    pop:
        return min( cacheheap, bigsortedlist )
    

    这可能是有效的如果 cacheheap 停留在真正的 cpu 缓存中; ymmv.
    (你也许可以作弊,让bigsortedlist 不准确,而不是每次都对其进行排序。)

    【讨论】:

      猜你喜欢
      • 2013-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-19
      相关资源
      最近更新 更多