要存储一个矩阵,std::vector 的嵌套并不是最好的解决方案。由于任何行都管理自己的大小,因此矩阵类没有固有的唯一列大小。
假设 OP 必须使用现有类型(可能不会更改),我基于此编写了示例。
一种解决方案(实施工作最少)是
- 将矩阵 (
std::vector<std::vector<std::string> >) 复制到 std::vector<std::string> 类型的临时文件中
- 申请
std::sort() 到这个临时的
- 再次将排序后的向量分配给矩阵。
考虑到元素的移动可能很昂贵,替代方法可能是
- 建立一个索引对向量
-
std::sort() 它带有一个自定义的 less 仿函数(考虑矩阵元素)。
之后,可以使用索引对向量按排序顺序访问原始矩阵元素。
后者显示在我的示例代码中:
#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
Life demo on coliru
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
Life demo on coliru
注意事项:
我使用了 cppreference.com 上的描述
作为“需求备忘单”并实现了其中描述的所有内容。一些细节,我凭猜测决定。 (特别是关于typedefs,我不太确定如何正确处理它们。)