【发布时间】:2019-04-26 22:19:10
【问题描述】:
我有一个动态的Matrix 模板类,我希望创建一个向量并使用沿列而不是行向下的索引填充它。您可能已经从我刚才所说的内容中猜到了,我将矩阵的实际数据以行主要形式存储在 std::vector<T> 中。这是我的 Matrix 类定义的简化版本,仅包含相关部分。
template<typename T>
class Matrix {
public:
Matrix(std::size_t m, std::size_t n, const T &elem = T());
Matrix(const std::vector<T> &vec, std::size_t m, std::size_t n);
Matrix(std::initializer_list<T> list, std::size_t m, std::size_t n);
private:
typedef std::vector<std::size_t> reindex_scheme;
std::vector<T> _data;
reindex_scheme _colindices;
std::size_t _m;
std::size_t _n;
};
基本上,我想要发生的是,当给出这段代码时:
std::vector<int> input {1, 2, 4, 6, 5, 4};
Matrix<int> A(input, 2, 3); // creates a 2x3 matrix with entries 1 2 4
// 6 5 4
让它按此顺序在_colindices 中存储以下内容:
0 3 1 4 2 5
(如果你明白我在做什么,如果你像这样遍历矩阵,我只是在抓取元素的索引:
| /| /|
| / | / |
\/ \/ \/
希望你能找出箭头)
到目前为止,我为构造函数提供的是“天真的”基于for 的方法:
template<typename T>
Matrix<T>::Matrix(std::size_t m, std::size_t n, const T &elem)
: _data(m * n, elem),
_colindices(m * n),
_m(m),
_n(n) {
for (std::size_t i = 0; i < _n; i++)
for (std::size_t j = 0; j < _m; j++)
_colindices[i * _m + j] = j * _n + i;
}
template<typename T>
Matrix<T>::Matrix(const std::vector<T> &vec, std::size_t m, std::size_t n)
: _data(vec),
_colindices(m * n),
_m(m),
_n(n) {
for (std::size_t i = 0; i < _n; i++)
for (std::size_t j = 0; j < _m; j++)
_colindices[i * _m + j] = j * _n + i;
}
template<typename T>
Matrix<T>::Matrix(std::initializer_list<T> list, std::size_t m, std::size_t n)
: _data(list),
_colindices(m * n),
_m(m),
_n(n) {
for (std::size_t i = 0; i < _n; i++)
for (std::size_t j = 0; j < _m; j++)
_colindices[i * _m + j] = j * _n + i;
}
另外,作为旁注,您可以看到我为三个构造函数所做的愚蠢的代码重复。如果您知道将三合一或至少三合二的最佳方法,也请在此处告诉我。(抱歉,这变成了一个双重问题)
这个for 方法有效,但显然它是O(mn),我喜欢认为有更好、更有效的方法,也许有一些std 方法?我正在考虑使用0 3 制作一个向量然后对其进行迭代,通过将每个元素增加std::transform 或其他内容来组成一个新向量,然后将其添加到最终向量的末尾,直到我到达结束(如果你明白我在说什么)。有点像
Loop Iteration 1:
0 3
Loop Iteration 2:
0 3 1 4
Loop Iteration 3:
0 3 1 4 2 5
你有什么想法?
【问题讨论】:
-
为什么需要存储这些索引?为什么不只计算某个访问器所需的索引?
-
除非您的目标是使用调试器检查内容,否则您展示的类没有任何用处。你打算如何访问这些元素?这是决定如何管理数据的关键。如果您打算使用迭代器(您可能应该这样做......),编写一个以行优先顺序访问存储数据的迭代器和另一个以列优先顺序访问存储数据的迭代器是相当简单的。
-
@PeteBecker 我是,我已经省略了 95% 的实际代码。计划使用
boost::permutation_iterator实现列优先迭代,并且由于数据以行优先形式存储,Matrix<T>::row_iterator实际上只是_data迭代器的类型定义。 -
permutation_iterator对于这样一个简单的映射来说听起来有点矫枉过正。只涉及两个数字:n 和 m,它们是已知的。将行重新映射到列的 nxm 矩阵(不管它是如何实现的)具有很多的冗余。 -
尽管有相反的传言,但迭代器并不难写。他们只是乏味。我经历了一个过程:输入迭代器的要求,输出迭代器的要求,前向迭代器的要求,双向迭代器的要求,随机访问迭代器的要求。每一个都增加了一些东西。
标签: c++ arrays performance vector std