我有一个大小超过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.
}
}
有没有办法让代码尽可能高效运行?任何想法都是受欢迎的,而不是有限的算法改进,例如,并行或其他任何东西。非常感谢你!
答案 0 :(得分:2)
如果Process_MyObj确实影响了A中所有元素的键,我认为你无能为力。如果它只修改了一些键,你可以编写代码来更新堆中的各个元素。
现在你的代码我看不到你从构建堆中获得了什么。我只是进行线性扫描以找到最小元素,将其与最后一个元素交换,然后弹出最后一个元素。
答案 1 :(得分:0)
您可以尝试按顺序对向量进行排序并选择元素,而不是使用堆。
它不会改善大的复杂性,但它可能会改善常数因素。
答案 2 :(得分:0)
Process_MyObj
中有多少时间,以及堆操作中有多少时间 -
50/50%,80/20%?
这很重要,因为你想要平衡两者。
请考虑以下常规设置:
Make a Todo list
Loop:
work on items ...
update the Todo list
更新列表的时间过长意味着没有足够的时间进行实际工作。
因此,首先测量过程/堆时间的比率
一个便宜的方法是做第二次运行
Process_MyObj
和compare
两次完成,例如
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位&lt; 32值,32索引&gt;比指针更有效率。
whats-new-in-purely-functional-data-structures-since-okasaki 在cstheory.stack上列出了数十篇论文,主要是理论论文, 但是一两个可能与你的问题有关。
真正的加速几乎总是针对特定问题,而不是一般的。 你能告诉我们更多有关真正问题的信息吗?
<小时/> 补充:如果大多数流行音乐很小,并推大, 尝试在大排序列表前面放一个小缓存。伪代码:
push:
push( cacheheap )
pop:
return min( cacheheap, bigsortedlist )
如果 cacheheap
保留在真正的cpu缓存中,这可能是有效的;因人而异。
(您可能会作弊,并使bigsortedlist
不准确,而不是每次都进行排序。)