使用stl排序将表排序到位

时间:2014-11-11 22:55:36

标签: c++ algorithm sorting stl

我有一个(i,j,k)格式的巨大表格(大约50Gb)(来自稀疏矩阵)存储为<​​/ p>

uint32_t * idx1, * idx2;
float * vals;
uint32_t tablesize;

我希望使用给定的比较函数对其进行排序,该函数是idx1和idx2的函数。可以使用std :: sort来完成吗?

具体地,通过将​​id放在idx1中的id,在idx2中的j,以及在val中的相应条目中的v,存储在稀疏矩阵中具有值v的每个非零条目(i,j)。我想根据(i1,j1,v1)&lt; =(i2,j2,v2)对这些条目进行排序,如果

(i1 < i2) || (i1==i2 && j1 <= j2)

我能够在非标准数据类型上使用std :: sort的例子假设被比较的每个项目是一个类的单个实例;这里每个项目由不同数组中的三个值表示。

2 个答案:

答案 0 :(得分:3)

遗憾的是,很难说服std::sort或任何标准库使用条带化数据。它旨在假设数据可以通过单个=复制,通过一个move移动或通过一个swap进行交换。

最好的办法是使用boost::iterator_facade编写一个包装数据的自定义迭代器类,并隐藏std::sort的条带化数据格式。我过去想做类似的事情,但我的工作区不允许我们使用boost编辑:当您的外观被取消引用时,可能需要创建某种可以分配/移动/交换的代理对象,并对每个条带数组执行正确的操作。这不是一件轻而易举的事。

下一个最好的选择是从0到N创建一个int的数组,每个数组代表条带数据数组的索引。写一个自定义仿函数给std::sort,它对这个数组进行排序以符合你的标准。当你有这么大的数据集时,它显然远非理想。

答案 1 :(得分:1)

如果您必须继续使用现有的数据结构(基本上是std::tuple三个std::vector,那么使用boost::zip_iterator 似乎将是要走的路。 zip_iterator将三个迭代器(两个索引和一个值)视为单个元组,您可以使用自定义比较函数对象对数据进行就地排序。唉,boost::zip_iterator无法与std::sort一起使用,如this Q&A中所述,因为它无法写入。

这意味着您必须编写自己的zip_iterator类,可以与std::sort一起使用。请注意,这不是一项简单的练习,请参阅this Q&A和/或此paper

std::vector的{​​{1}}进行排序要容易得多。我在下面的尝试使用std::tuple两个索引和一个值,并将这些条目存储到std::tuple中。对于排序,我使用C ++ 14泛型lambda,将两个索引转发为一个较小的元组,并使用std::vector的{​​{1}}字符串按字典顺序(即首先在行索引上,然后在列索引上)进行比较。 {1}}。

operator<

Live Example

如果您的应用程序可以使用此转换后的数据布局(并且可能存在缓存性能原因,那么上面的代码将根据您的需要进行排序。

注意:正如@Casey所提到的,您也可以使用std::tuple代替#include <algorithm> #include <iostream> #include <tuple> #include <vector> using index = uint32_t; using value = float; using sparse_entry = std::tuple<index, index, value>; using sparse_matrix = std::vector<sparse_entry>; int main() { // sparse 3x3 matrix auto m = sparse_matrix { std::make_tuple( 1, 1, -2.2), std::make_tuple( 1, 0, 42 ), std::make_tuple( 0, 2, 3.4), std::make_tuple( 0, 1, 1.7) }; // sort by row-index, then column-index std::sort(begin(m), end(m), [](auto const& L, auto const& R) { return std::forward_as_tuple(std::get<0>(L), std::get<1>(L)) < std::forward_as_tuple(std::get<0>(R), std::get<1>(R)) ; }); for (auto const& elem : m) std::cout << "{ " << std::get<0>(elem) << ", " << std::get<1>(elem) << ", " << std::get<2>(elem) << "}, \n"; } ,但是当您将std::tie更改为完整内容时,这可能会让您感到困惑成熟的用户定义类,其中getters按值返回。