使用 std::sort 对矩阵进行排序

Using std::sort to sort Matrix

本文关键字:排序 std sort 使用      更新时间:2023-10-16

有没有办法使用 std 中的排序函数对矩阵元素进行排序?

//Using this matrix
vector<vector<string>> mat;

例如,如果您有

5 2 1
0 0 2
1 4 3

结果将是

0 0 1
1 2 2
3 4 5

要存储矩阵,嵌套std::vector不是最佳解决方案。由于任何行都管理自己的大小,因此矩阵类本身没有授予的唯一列大小。

假设 OP 被诅咒使用现有类型(可能不会更改(,我基于此编写了我的示例。

一种解决方案(实施工作量最少(是

  1. 将矩阵 (std::vector<std::vector<std::string> >( 复制到std::vector<std::string>类型的临时矩阵中
  2. std::sort()适用于此临时
  3. 再次将排序后的向量分配给矩阵。

考虑到元素的移动可能很昂贵,另一种选择可能是

  1. 构建索引对向量
  2. 使用自定义的更少函子(考虑矩阵元素(std::sort()它。

之后,索引对向量可用于按排序顺序访问原始矩阵元素。

后者显示在我的示例代码中:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
typedef std::vector<std::string> Row;
typedef std::vector<Row> Matrix;
typedef std::pair<size_t, size_t> IndexPair;
struct LessMatrix {
const Matrix &mat;
LessMatrix(const Matrix &mat): mat(mat) { }
bool operator()(const IndexPair &i1, const IndexPair &i2)
{
return mat[i1.first][i1.second] < mat[i2.first][i2.second];
}
};
std::ostream& operator<<(std::ostream &out, const Matrix &mat)
{
for (const Row row : mat) {
for (const std::string elem : row) out << ' ' << elem;
out << 'n';
}
return out;
}
int main()
{
Matrix mat = {
{ "5", "2", "1" },
{ "0", "0", "2" },
{ "1", "4", "3" }
};
// print input
std::cout << "Input:n" << mat << 'n';
// indexify matrix
std::vector<IndexPair> indices;
for (size_t i = 0, n = mat.size(); i < n; ++i) {
const std::vector<std::string> &row = mat[i];
for (size_t j = 0, m = row.size(); j < m; ++j) {
indices.push_back(std::make_pair(i, j));
}
}
// sort matrix
LessMatrix less(mat);
std::sort(indices.begin(), indices.end(), less);
// print output
Matrix matOut;
{ size_t i = 0; const size_t nCols = 3;
for (const IndexPair &index : indices) {
if (i % nCols == 0) matOut.push_back(Row());
matOut.back().push_back(mat[index.first][index.second]);
++i;
}
}
std::cout << "Output:n" << matOut << 'n';
// done
return 0;
}

输出:

Input:
5 2 1
0 0 2
1 4 3
Output:
0 0 1
1 2 2
3 4 5

科里鲁的生活演示


OP 抱怨创建一个单独的索引向量。我怀疑自定义随机访问迭代器可能是替代品(直接对矩阵进行排序(。我必须承认我以前没有这样做过,但是出于好奇,我试图解决这个问题:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cassert>
typedef std::vector<std::string> Row;
typedef std::vector<Row> Matrix;
struct MatrixIterator {
typedef size_t difference_type;
typedef std::string value_type;
typedef std::string* pointer;
typedef std::string& reference;
typedef std::random_access_iterator_tag iterator_category;
// accessed matrix
Matrix &mat;
// index of row, index of column
size_t i, j;
MatrixIterator(Matrix &mat, size_t i = 0, size_t j = 0): mat(mat), i(i), j(j) { }
MatrixIterator& operator =(const MatrixIterator &iter)
{
assert(&mat == &iter.mat);
i = iter.i; j = iter.j;
return *this;
}
size_t nCols() const { return mat.front().size(); }
std::string& operator *() { return mat[i][j]; }
const std::string& operator *() const { return mat[i][j]; }
MatrixIterator& operator ++() { return *this += 1; }
MatrixIterator operator ++(int) { MatrixIterator iter(*this); ++*this; return iter; }
MatrixIterator& operator --() { return *this -= 1; }
MatrixIterator operator --(int) { MatrixIterator iter(*this); --*this; return iter; }
MatrixIterator& operator += (size_t n)
{
j += i * nCols() + n; i = j / nCols(); j %= nCols(); return *this;
}
MatrixIterator operator + (size_t n) const
{
MatrixIterator iter(*this); iter += n; return iter;
}
friend MatrixIterator operator + (size_t n, const MatrixIterator &iter)
{
MatrixIterator iter2(iter); iter2 += n; return iter2;
}
MatrixIterator& operator -= (size_t n)
{
j += i * nCols() - n; i = j / nCols(); j %= nCols();
return *this;
}
MatrixIterator operator - (size_t n) const
{
MatrixIterator iter(*this); iter -= n; return iter;
}
size_t operator - (const MatrixIterator &iter) const
{
return (i * nCols() + j) - (iter.i * iter.nCols() + iter.j);
}
std::string& operator[](size_t i) { return mat[i / nCols()][i % nCols()]; }
const std::string& operator[](size_t i) const { return mat[i / nCols()][i % nCols()]; }
bool operator == (const MatrixIterator &iter) const
{
return i == iter.i && j == iter.j;
}
bool operator != (const MatrixIterator &iter) const { return !(*this == iter); }
bool operator < (const MatrixIterator &iter) const
{
return i * nCols() + j < iter.i * iter.nCols() + iter.j;
}
bool operator > (const MatrixIterator &iter) const { return iter < *this; }
bool operator <= (const MatrixIterator &iter) const { return !(iter > *this); }
bool operator >= (const MatrixIterator &iter) const { return !(*this < iter); }
};
MatrixIterator begin(Matrix &mat) { return MatrixIterator(mat, 0, 0); }
MatrixIterator end(Matrix &mat) { return MatrixIterator(mat, mat.size(), 0); }
std::ostream& operator<<(std::ostream &out, const Matrix &mat)
{
for (const Row row : mat) {
for (const std::string elem : row) out << ' ' << elem;
out << 'n';
}
return out;
}
int main()
{
Matrix mat = {
{ "5", "2", "1" },
{ "0", "0", "2" },
{ "1", "4", "3" }
};
// print input
std::cout << "Input:n" << mat << 'n';
// sort matrix
std::sort(begin(mat), end(mat));
// print output
std::cout << "Output:n" << mat << 'n';
// done
return 0;
}

输出:

Input:
5 2 1
0 0 2
1 4 3
Output:
0 0 1
1 2 2
3 4 5

科里鲁的生活演示

笔记:

我使用了 cppreference.com 的描述

  • C++概念:随机访问迭代器
  • C++概念:双向迭代器
  • C++概念:前向迭代器
  • C++概念:迭代器
  • 标准::iterator_traits

作为"需求备忘单"并实现了那里描述的所有内容。一些细节,我猜猜决定。(特别是,关于typedef,我不太确定如何正确处理它们。

您可以通过创建自定义包装矩阵类并定义自己的迭代器来对嵌套向量进行排序,而无需复制额外的数据:

#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
class MyMatrix {
public:
using DataStore = std::vector<std::vector<std::string> >;
// Note: Make sure MyMatrix DO NOT out-live its `data` argument!
MyMatrix(DataStore& data) : data_(data) {
// Check that
//  1. data.size() > 0;
//  2. data[i].size() > 0 and same for all valid i.
}
class Iterator : public std::iterator<std::random_access_iterator_tag,
std::string, int> {
public:
Iterator(DataStore& data) : data_(&data), index_(0) {}
Iterator(DataStore& data, int index) : data_(&data), index_(index) {}
Iterator(const Iterator& it) : data_(it.data_), index_(it.index_) {}
Iterator& operator=(const Iterator& it) {
data_ = it.data_;
index_ = it.index_;
}
operator bool() const {
return index_ >= 0 && index_ < data_->size() * (*data_)[0].size();
}
bool operator==(const Iterator& it) const {
return data_ == it.data_ && index_ == it.index_;
}
bool operator!=(const Iterator& it) const {
return data_ != it.data_ || index_ != it.index_;
}
Iterator& operator++() { ++index_; return *this; }
Iterator& operator--() { --index_; return *this; }
Iterator operator++(int) { return Iterator(*data_, index_++); }
Iterator operator--(int) { return Iterator(*data_, index_--); }
Iterator& operator+=(int offs) { index_ += offs; return *this; }
Iterator& operator-=(int offs) { index_ -= offs; return *this; }
Iterator operator+(int offs) { return Iterator(*data_, index_ + offs); }
Iterator operator-(int offs) { return Iterator(*data_, index_ - offs); }
int operator-(const Iterator& it) { return index_ - it.index_; }
std::string& operator*() {
return (*data_)[index_ / data_->size()][index_ % (*data_)[0].size()];
}
const std::string& operator*() const { return operator*(); }
private:
DataStore* data_;
int index_;
}; // class Iterator
Iterator iterator() { return Iterator(data_); }
Iterator begin() { return Iterator(data_, 0); }
Iterator end() { return Iterator(data_, data_.size() * data_[0].size()); }
private:
DataStore& data_;
};  // class MyMatrix

然后sort可以应用于MyMatrix,如下所示:

#include <iostream>
int main()
{
std::vector<std::vector<std::string> > store = {
{ "5", "2", "1" },
{ "0", "0", "2" },
{ "1", "4", "3" }
};
MyMatrix matrix(store);
for (const auto& row : store) {
for (const auto& item : row) { std::cout << item <<' '; }
std::cout <<'n';
}
std::cout <<'n';
std::sort(matrix.begin(), matrix.end());
for (const auto& row : store) {
for (const auto& item : row) { std::cout << item <<' '; }
std::cout <<'n';
}
std::cout <<'n';
}

运行上述代码将导致以下输出:

5 2 1 
0 0 2 
1 4 3 
0 0 1 
1 2 2 
3 4 5