C++ 使用stl排序就地排序表
我有一个(I,j,k)格式的巨大表(大约50Gb)(来自稀疏矩阵)存储为C++ 使用stl排序就地排序表,c++,algorithm,sorting,stl,C++,Algorithm,Sorting,Stl,我有一个(I,j,k)格式的巨大表(大约50Gb)(来自稀疏矩阵)存储为 uint32_t * idx1, * idx2; float * vals; uint32_t tablesize; 我想用一个给定的比较函数对它进行排序,它是idx1和idx2的函数。这可以使用std::sort完成吗 具体而言,稀疏矩阵中具有值v的每个非零条目(i,j)通过将i放置在idx1中、j放置在idx2中、v放置在vals中的相应条目中来存储。然后我想根据(i1,j1,v1)对这些条目进行排序不幸的是,很难说
uint32_t * idx1, * idx2;
float * vals;
uint32_t tablesize;
我想用一个给定的比较函数对它进行排序,它是idx1和idx2的函数。这可以使用std::sort完成吗
具体而言,稀疏矩阵中具有值v的每个非零条目(i,j)通过将i放置在idx1中、j放置在idx2中、v放置在vals中的相应条目中来存储。然后我想根据(i1,j1,v1)对这些条目进行排序不幸的是,很难说服
std::sort
,或任何标准库使用条带化数据。其设计目的是假设数据可以通过单个=
进行复制,通过一个移动
进行移动,或通过一个交换
进行交换
最好的方法是使用boost::iterator\u facade
编写一个自定义迭代器类来包装数据,并从std::sort
中隐藏条带化数据格式。我过去也想做类似的事情,但我的工作区不允许我们使用boost
编辑:当您的外观被取消引用时,它可能需要创建某种代理对象,该对象可以被分配/移动/交换,并对每个条带阵列执行正确的操作。这不是小事
下一个最好的选择是将
int
s从0到N组成一个数组,每个数组代表条带化数据数组中的一个索引。编写一个自定义函子到std::sort
,该函子对该数组进行排序以符合您的条件。当您拥有如此大的数据集时,这显然远远不够理想。如果您必须继续使用现有的数据结构,它本质上是三个std::vector
的tuple
,那么使用boost::zip\u迭代器似乎是一种可行的方法。zip_迭代器
将三个迭代器(两个用于索引,一个用于值)视为一个元组,您可以使用自定义比较函数对象对数据进行就地排序。唉,boost::zip_迭代器
不能与std::sort
一起使用,如中所述,因为它不能写入
这意味着您必须编写自己的zip_迭代器类,该类可以与std::sort
一起使用。请注意,这不是一个简单的练习,请参见和/或此
对std::tuple
的std::vector
进行排序要容易得多。下面我尝试使用两个索引和一个值的std::tuple
,并将这些条目存储到std::vector
中。对于排序,我使用一个C++14通用lambda,它将两个索引转发到一个较小的元组中,并使用库运算符按字典顺序(即,首先在行索引上,然后在列索引上)比较这些索引。简言之,请查看std::sort
的3参数版本,然后查找函子
或函数对象
。因此您需要提供帮助--如果我给您两个(I,j,k)值,那么告诉我们如何确定第一个值是否在第二个值之前。这张桌子是什么形状的?您需要更详细地告诉我们这些数据是如何构造的。那么您想对所有三个数组进行排序吗?最简单的方法是将它们组合成一个struct
,只需要一个该类型的数组,我不知道如何使用sort的三参数版本。随机访问迭代器在这里是什么?这就是我关于非标准数据类型的意思:如果您的值按照Jonathan的建议存储为单个类对象,那么可以使用示例来处理此类问题(这对我来说是不可行的,因为构建这样的结构作为数据的第二个副本会耗尽内存),但是,如果你的数据分布在多个数组中,没有什么问题。我认为这个答案最接近你想要的,但是你可能想考虑为真正巨大的数组优化你自己的排序。50 GB的数据,即使RAM中的数据通过外部排序算法得到更好的处理,以更好地利用访问的局部性;这也是一个公平的赌注,你也将受益于并行排序。好的观点。我的回答是“你能在这里使用std::sort
”而不是“你应该”。我上面列出的所有技巧可能比复制粘贴一个基本的qsort
实现并调整它以满足您的需要更费劲,手动调整的实现也可能更快。取消引用时返回代理的迭代器不是RandomAccessIterator,因为ForwardIterator取消引用时,需要返回value\u-type&
或const-value\u-type&
。(根据[forward.iterators]/1.3)std::tie
比std::forward_as_tuple
键入速度快一点,在这种情况下也有相同的效果。@Caseystd::tie
只接受左值,而std::forward_as_tuple
也适用于按值返回的getter。另外,std::tie
不是constepr>,因此我养成了不使用std::tie
的习惯。没有按值返回的std::get
重载,而且几乎不可能扩展,因为(a)禁止在std
中重载函数,以及(b)部分专门化函数是不可能的。当传递左值时,这样的扩展按值返回也是相当不合理的。在任何情况下,我确实编辑了我的注释,添加了“在这个实例中”;@Casey更新了我的答案,tnx!顺便说一句,使用getter,您可以编写类似于std::tie(L.row(),L.column())
的内容,而不是std::get
,当然是这样。我把你评论中的“getters”误认为是std::get
的味道。现在这更有意义了。
(i1 < i2) || (i1==i2 && j1 <= j2)
#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";
}