gpt4 book ai didi

c++ - 为 Matrix 设计一个简单的 C++ 迭代器

转载 作者:行者123 更新时间:2023-11-27 23:39:12 24 4
gpt4 key购买 nike

我正在考虑设计一个简单的 C++ 迭代器,其 ++ 操作对于像 STL 一样的向后和向前迭代表现不同。这样矩阵 A 可以通过行和列访问,如下所示,

  A.row(3).begin()
A.row(3).end()
A.col(3).begin()
A.col(3).end()
A.col(3).rbegin()
A.col(3).rend()

++ A.row(3).begin()
++ A.col(3).rbegin()

我的矩阵类如下所示,

class Matrix {
public:
Iter row(size_t rowID);
Iter col(size_t colID);
private:
vector<int> data_{1, 2, 3, 4, 5, 6};
size_t nRow{3};
size_t nCol{2};
};

对于如何设计我的 Iter 类有什么建议吗?

最佳答案

这里是没有提升的 C++ 解决方案。我还提供了完整且经过测试的源代码示例。

源码使用MS Visual Studio 19编译测试。

第一个提示:我总是使用 std::valarray 进行矩阵计算。请阅读它。

对该方案的解释:

我们将使用 int vector 的 vector 来表示矩阵。可以轻松访问行。它们是数据矩阵的第一维。如果我们想要一行的迭代器,我们简单地返回一个 vector 的标准迭代器。这样,我们将立即拥有完整的功能。简单。

不幸的是列不同。它们是数据连续内存中的切片。因此,我们将实现的解决方案是:为每一列创建一个 vector ,并引用正确位置的数据。

这听起来比实际更容易,因为我们不能在 C++ 中的容器中存储引用。因此,要么使用 std::reference_wrapper,要么构建我们自己的引用包装器。我在为取消引用的 std::reference_wrapper 赋值并构建自己的值时遇到了问题。添加了赋值运算符。

有了它,我们可以根据引用 vector 将迭代器返回到列。

而且,我们通过简单地重用 std::vector::iterator 功能,以最小的努力拥有矩阵类迭代器的全部功能。

我在main里放了一些测试代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <tuple>
#include <sstream>
#include <numeric>


// Unfortunately the std::reference_wrapper does not work as expected.
// So we will build our own one
class IntRef
{
// Here we will store the reference
std::tuple<int&> t;
public:
// Constructor. Take reference and store it in tuple
IntRef(int&& intV) : t(intV) {}

// Assignment to the referenced value
int operator =(const int i) { std::get<0>(t) = i; return i; }

// Explicit type cast to int&
operator int& () { return std::get<0>(t); }

// And, return the reference
decltype(&std::get<0>(t)) operator&() { return &std::get<0>(t); }
};


// Some definitions to make reading easier
using IntRefV = std::vector<IntRef>;
using MatrixCIterator = std::vector<IntRef>::iterator;
using Columns = std::vector<int>;
using MatrixRIterator = Columns::iterator;


// The matrix
class Matrix
{
public:
// Constructor defines the matrix size
Matrix(size_t numberOfRows, size_t numberOfColumns);

// Iterators for rows are simple, becuase we have vectors of columns. Use unterlying iterator
MatrixRIterator rowIterBegin(size_t row) { return data[row].begin(); }
MatrixRIterator rowIterEnd(size_t row) { return data[row].end(); }

// Column iterator is complicated. Retzurn iterator to vevtor of references to column values
MatrixCIterator columnIterBegin(size_t column) { return columnReferences[column].begin(); }
MatrixCIterator columnIterEnd(size_t column) { return columnReferences[column].end(); }

// Access data of matrix
std::vector<int>& operator [] (const size_t row) { return data[row]; }

// And, for debug purposes. Output all data
friend std::ostream& operator << (std::ostream& os, const Matrix& m) {
std::for_each(m.data.begin(), m.data.end(), [&os](const Columns& columns) {std::copy(columns.begin(), columns.end(), std::ostream_iterator<int>(os, " ")); std::cout << '\n'; });
return os;
}
protected:
//The matrix, vector of vector of int
std::vector<Columns> data;

// The references to columns in data
std::vector<IntRefV> columnReferences{};
};

// Constructor. Build basic matrix and then store references to columns in data
Matrix::Matrix(size_t numberOfRows, size_t numberOfColumns) : data(numberOfRows, std::vector<int>(numberOfColumns)), columnReferences(numberOfColumns)
{
for (size_t column = 0; column < numberOfColumns; ++column)
for (size_t row = 0; row < numberOfRows; ++row)
columnReferences[column].emplace_back(IntRef(std::move(data[row][column]))); // Std::move creates a rvalue reference (needed for constructor, nothing will be moved)
}



// Some test data for the istream_iterator
std::istringstream testData("1 2 10");



// Test the matrix
int main()
{
// Define a matrix with 3 rows and 4 columns
Matrix matrix(3, 4);
// Test 1: Fill all values in column 2 with 42
for (MatrixCIterator ci = matrix.columnIterBegin(2); ci != matrix.columnIterEnd(2); ++ci) {
*ci = 42;
}
std::cout << matrix << "Column 2 filled with 42\n\n";

// Test 2: Read input from istream and copy put that in column 1
std::copy_n(std::istream_iterator<int>(testData), 3, matrix.columnIterBegin(1));
std::cout << matrix << "Column 1 filled with testData '"<< testData.str() << "'\n\n";

// Test 3: Copy column 2 to cout (Print column 2)
std::copy(matrix.columnIterBegin(2), matrix.columnIterEnd(2), std::ostream_iterator<int>(std::cout, " "));
std::cout << "This is column 2\n\n";

// Test 4: Sum up the first 2 values of column 1 and show result
std::cout << "\nSum of first 2 values of column 1: " << std::accumulate(matrix.columnIterBegin(1), matrix.columnIterBegin(1)+2, 0) << "\n\n";

// Test 5: Fill all values in row 0 with 33
std::for_each(matrix.rowIterBegin(0), matrix.rowIterEnd(0), [](int& i) { i = 33; });
std::cout << matrix << "Row 0 filled with 33\n\n";

return 0;
}

希望这能让您了解它的工作原理。 . .

关于c++ - 为 Matrix 设计一个简单的 C++ 迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56816493/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com