【发布时间】:2012-07-18 17:07:20
【问题描述】:
问题
假设我有一个包含一些数据的大字节数组(最多 4GB)。这些字节对应于不同的对象,每个 s 个字节(认为 s 最多 32 个)将构成一个对象。一个重要的事实是,这个大小 s 对于所有对象都是相同的,不存储在对象本身中,在编译时也不知道。
目前,这些对象只是逻辑实体,而不是编程语言中的对象。我对这些对象进行了比较,其中包括对大多数对象数据的字典比较,以及一些不同的功能来使用剩余数据打破联系。现在我想有效地对这些对象进行排序(这确实会成为应用程序的瓶颈)。
目前的想法
我已经想到了几种可能的方法来实现这一点,但每种方法似乎都会产生一些相当不幸的后果。您不必阅读所有这些内容。 我尝试用粗体打印每种方法的中心问题。 如果您要建议其中一种方法,那么您的答案应该是回应以及相关的问题。
1。 C 快速排序
当然,C 快速排序算法也可用于 C++ 应用程序。它的签名几乎完全符合我的要求。但是,使用该函数将禁止比较函数的内联,这意味着每次比较都会带来函数调用开销。我曾希望有一种方法可以避免这种情况。 非常欢迎任何关于 C qsort_r 在性能方面与 STL 相比的经验。
2。间接使用指向数据的对象
很容易编写一堆对象来保存指向它们各自数据的指针。然后可以对这些进行排序。这里有两个方面需要考虑。一方面,仅仅围绕指针而不是所有数据移动意味着更少的内存操作。另一方面,不移动对象可能会破坏内存局部性,从而破坏缓存性能。更深层次的快速排序递归实际上可以从几个缓存页面访问所有数据的机会几乎完全消失了。相反,每个缓存的内存页面在被替换之前只会产生很少的可用数据项。 如果有人能提供一些关于复制和内存局部性之间权衡的经验,我将非常高兴。
3。自定义迭代器、引用和值对象
我写了一个类作为内存范围的迭代器。取消引用这个迭代器不会产生一个引用,而是一个新构造的对象来保存指向数据的指针和在迭代器构造时给出的大小 s。所以可以比较这些对象,我什至有一个std::swap 的实现。不幸的是,std::swap 似乎对std::sort 来说还不够。在过程的某些部分,我的 gcc 实现使用插入排序(如在文件 stl_alog.h 中的 __insertion_sort 中实现的那样),它将一个值移出序列,将一个数字项移动一步,然后将第一个值移回在适当的位置进入序列:
typename iterator_traits<_RandomAccessIterator>::value_type
__val = _GLIBCXX_MOVE(*__i);
_GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1);
*__first = _GLIBCXX_MOVE(__val);
您知道不需要值类型但可以单独使用交换操作的标准排序实现吗?
所以我不仅需要我的类作为参考,还需要一个类来保存临时值。由于我的对象的大小是动态的,我必须在堆上分配它,这意味着内存分配在 recursion 树的叶子上。也许另一种选择是具有静态大小的 vaue 类型,该大小应该足够大以容纳我目前打算支持的大小的对象。但这意味着迭代器类的reference_type 和value_type 之间的关系会更加骇人听闻。这意味着我必须将我的应用程序的大小更新为有朝一日支持更大的对象。丑。
如果您能想出一种简洁的方法来让上述代码操作我的数据而不必动态分配内存,那将是一个很好的解决方案。我正在使用 C++11 功能已经,所以使用移动语义或类似的不会有问题。
4。自定义排序
我什至考虑重新实现所有快速排序。也许我可以利用我的比较主要是字典比较的事实,即我可以按第一个字节对序列进行排序,只有当所有元素的第一个字节都相同时才切换到下一个字节。我还没有弄清楚这方面的细节,但是如果有人可以建议一个参考、一个实现甚至是一个规范的名称来用作这种按字节排序的字典排序的关键字,我会非常很高兴。我仍然不相信通过我的合理努力,我可以击败 STL 模板实现的性能。
5。完全不同的算法
我知道那里有很多种排序算法。其中一些可能更适合我的问题。 基数排序首先出现在我的脑海中,但我还没有真正考虑过这一点。 如果您能提出更适合我的问题的排序算法,请这样做。最好有实施,但即使没有。
问题
所以基本上我的问题是这样的:
“如何有效地对堆内存中动态大小的对象进行排序?”
任何适用于我情况的问题的答案都是好的,无论它是否与我自己的想法有关。对以粗体标记的个别问题的答案,或任何其他可能有助于我在备选方案之间做出决定的见解,也会很有用,尤其是在没有针对单一方法的明确答案出现的情况下。
【问题讨论】:
标签: c++ sorting stl g++ stl-algorithm