我有一个1000-2000个元素的数组,它们是指向对象的指针。我想保持我的数组排序,显然我想尽快做到这一点。它们按成员排序而不是连续分配,因此每当我访问sort-by成员时都会假设缓存未命中。
目前我按需排序而不是on-add,但由于缓存未命中和[推测]非内联成员访问,我的快速排序的内循环很慢。
我现在正在做测试和尝试,(看看实际的瓶颈是什么)但是有人可以推荐一个很好的替代方案来加速这个吗? 我应该进行插入排序而不是按需快速排序,还是应该尝试更改模型以使元素变得有意义并减少缓存未命中? 或者,是否有一种排序算法我没有遇到哪种方法对于缓存未命中的数据有用?
编辑:也许我措辞错误:),我实际上并不需要我的数组一直排序(我没有顺序迭代它们的任何东西)我只是需要它排序当我做二进制印章找到一个匹配的对象,并在那个时候(当我想搜索时)做那个快速排序当前是我的瓶颈,因为缓存未命中和跳转(我在我的对象上使用<操作符,但我希望在发布中内联)
答案 0 :(得分:2)
在每次插入时运行快速排序是非常低效的。执行二进制搜索和插入操作可能会快几个数量级。使用二叉搜索树而不是线性数组会降低插入成本。
编辑:我错过了你对提取进行排序,而不是插入。无论如何,保持排序可以分摊每个插入的排序时间,这几乎必须是一个胜利,除非你每次提取都有很多插入。
如果你想保持排序提取方法,那么可能会切换到合并排序,或者对大多数排序数据具有良好性能的其他排序。
答案 1 :(得分:1)
我认为在您的情况下,最好的方法是将数据结构更改为对数并重新考虑您的体系结构。因为你的应用程序的瓶颈不是那个排序的东西,但问题 为什么你必须对每个插件上的所有内容进行排序并尝试通过添加按需排序来补偿它? 强>
你可以尝试的另一件事(基于你当前的实现)正在实现一个外部pointer - something
映射表/函数并对那些第二个键进行排序,但我实际上怀疑它会有什么好处在这种情况下。
答案 2 :(得分:1)
简单方法:在每个插入上插入排序。由于你的元素没有在内存中对齐,我猜测链表。如果是这样,那么您可以将其转换为链接列表,跳转到第10个元素,第100个元素,依此类推。这有点类似于下一个建议。
或者您将容器结构重新组织成二叉树(或您喜欢的每棵树,B,B *,红黑,......)并插入元素,就像将它们插入搜索树一样。
答案 3 :(得分:1)
正如您所提到的,您将不得不进行一些分析,以确定这是否是一个瓶颈,以及其他方法是否能提供任何缓解。
使用数组的替代方法是std::set或std::multiset,它们通常实现为R-B二叉树,因此对大多数应用程序具有良好的性能。您将不得不使用它们来衡量您实施的排序时搜索模式的频率。
在任何一种情况下,除非您对learning more about how it's done.
感兴趣,否则我不建议您自己进行排序或搜索答案 4 :(得分:1)
您可以考虑一个结构数组,而不是指针数组,该结构数组包含指向对象的指针和排序条件。那就是:
而不是
struct MyType {
// ...
int m_SomeField; // this is the sort criteria
};
std::vector<MyType*> arr;
你可以这样做:
strcut ArrayElement {
MyType* m_pObj; // the actual object
int m_SortCriteria; // should be always equal to the m_pObj->m_SomeField
};
std::vector<ArrayElement> arr;
如果您只通过此阵列访问对象,也可以从结构中删除m_SomeField
字段。
通过这样排序您的数组,您不需要在每次迭代时取消引用m_pObj
。因此,您将使用缓存。
当然,您必须始终将m_SortCriteria
与对象的m_SomeField
保持同步(如果您正在编辑它)。
答案 5 :(得分:0)
我认为插入排序会更好。我们在这里讨论O(log N)比较,所以说ceil( O(log N) ) + 1
检索要排序的数据。
对于2000年,它相当于:8
这有什么好处,你可以缓冲要插入的元素的数据,这就是你只有8个函数调用来实际插入。
你可能希望看一些内联,但在你确定这是一个紧张的地方之前做个人资料。