如何枢轴向量的向量

How to pivot a vector of vectors

本文关键字:向量 何枢轴      更新时间:2023-10-16

我正在寻找一种优雅的方式来使用 STL 算法或提升预先枢轴向量向量示例数据如下所示

vector<vector<int> > vm;
vector<int> v;
v.push_back(1);
v.push_back(2);
vm.push_back(v);
v.clear();
v.push_back(3);
v.push_back(4);
vm.push_back(v);
v.clear();
v.push_back(5);
v.push_back(6);
vm.push_back(v);
1   2
3   4
5   6

我想得到这样的整数向量

1   3   5
2   4   6

我想最简单的解决方案就是编写一个简单的transpose函数,其中包含两个循环:

std::vector<std::vector<int> > transpose(const std::vector<std::vector<int> > data) {
    // this assumes that all inner vectors have the same size and
    // allocates space for the complete result in advance
    std::vector<std::vector<int> > result(data[0].size(),
                                          std::vector<int>(data.size()));
    for (std::vector<int>::size_type i = 0; i < data[0].size(); i++) 
        for (std::vector<int>::size_type j = 0; j < data.size(); j++) {
            result[i][j] = data[j][i];
        }
    return result;
}

按值返回应该足够容易地优化。我不认为使用任何标准功能会变得更简单或更高效,但我可能是错的。

另一种方法是将所有数据存储在一个平面vector中,然后使用i*row_length + j或类似的东西计算元素i, j的位置。这样,转置不涉及复制数据,而只需更改索引的计算即可。

看看Boost MultiArray。您可以创建数据的子视图。还有具有转置方法的vnl_matrix。

我会介绍一个包装器,它将行 -> col 和 col -> 行转换为行。这将防止您必须复制所有数据。

#include <iostream>
#include <vector>
template<typename T>
class TwoDPivotWrapper
{
    public:
        // These two typedef's were done with std::vector
        // in mind. But with a small amount of effort I am
        // sure they can be generalized. They are solely to define
        // value_type (the data stored in the 2-D array).
        typedef typename T::value_type          OneDType;
        typedef typename OneDType::value_type   value_type;
        // A constructor that wraps a 2-D structure.
        TwoDPivotWrapper(T& o)
            : object(o)
        {}
        // A helper class used to store the row after the first array accesses.
        class Row
        {
            friend class TwoDPivotWrapper;
            Row(TwoDPivotWrapper& w, size_t r)
                : wrapper(w)
                , row(r)
            {}
            TwoDPivotWrapper&    wrapper;  
            size_t               row;
            public:
                value_type operator[](size_t col)
                {                    
                    return wrapper.get(row,col);
                }
        };
        // The operator [] returns a Row object that overloads
        // the operator[] for the next dimension.
        Row operator[](size_t row)              {return Row(*this, row);}
        // Generic get function used to access elements.
        // Notice we swap the row/col around when accessing
        // the underlying object.
        value_type get(size_t row, size_t col)  {return object[col][row];}
    private:
        T&  object;
};

典型用法是:

int main()
{
    typedef std::vector<std::vector<int> >      TwoDVector;
    TwoDVector  data(3,std::vector<int>(2,0));
    data[0][0]  = 1; data[0][1]  = 2;
    data[1][0]  = 3; data[1][1]  = 4;
    data[2][0]  = 5; data[2][1]  = 6;
    TwoDPivotWrapper<TwoDVector>               wrapper(data);
    std::cout << wrapper[0][0] << wrapper[0][1] << wrapper[0][2] << "n";
    std::cout << wrapper[1][0] << wrapper[1][1] << wrapper[1][2] << "n";
}
如果你

打算在C++做很多线性代数,你应该看看Boost.uBlas。

#include <boost/numeric/ublas/matrix.hpp>
template <class M>
void printMatrix(const M& m)
{
    for (size_t i=0; i<m.size1(); ++i)
    {
        for (size_t j=0; j<m.size2(); ++j)
            std::cout << m(i,j) << " ";
        std::cout << std::endl;
    }
}
int main()
{
    namespace ublas = boost::numeric::ublas;
    typedef ublas::matrix<double> Matrix;
    Matrix A(3, 2);
    // Fill matrix A with incrementing values
    double counter = 0.0;
    for (size_t i=0; i<A.size1(); ++i)
        for (size_t j=0; j<A.size2(); ++j)
            A(i,j) = ++counter;
    printMatrix(A);
    std::cout << std::endl;
    // Transpose A and store it in B
    Matrix B = ublas::trans(A);
    printMatrix(B);
    return 0;
}

它一定要是向量的向量吗?

如果没有,那么您可能会在行*列元素的常规向量上实现包装器。

像这样:

class Vector
{
public:
    int operator[]( int index )
    {
        return 1;
    }
    friend class Wrapper;
private:
    Vector( std::vector<int> & vector, int index, int numElements );
    std::vector<int> v_;
    int index_;
    int numElements_;
};
class Wrapper
{
public:
    Vector operator[](int index)
    {
        return Vector( v_, index, numColumns_ );
    }
    Wrapper( int numRows, int numColumns);
    void setNumRows( int numRows );
    void setNumColumns( int numColumns );
private:
    std::vector<int> v_;
    int numRows_;
    int numColumns_;
};

主要:

Wrapper w;
int i = w[1][1];

编辑:

Vector 类将表示行或列数据。作为参数,它需要线性化矩阵、矩阵几何形状(行数和列数)以及它所代表的行/列。

用铅笔和纸试试这个:1. 以矩阵形式编写 3x4 矩阵的元素

11 12 13 1421 22 23 2431 32 33 34

  1. 以线性方式编写它们:
11 12 13 14 21 22

23 24 31 32 33 34

矩阵形式的

元素索引与其线性化形式的索引之间存在简单的关系,这取决于矩阵几何形状。

  1. 如果您希望 Vector "包含"元素 21 22 23 24(或 12 22 32),那么您需要在运算符 [](int index)中实现一些逻辑,该逻辑将确定来自 Vector[index] 的元素底层向量中的索引。

假设您的 Vector 需要引用矩阵中的第二列(即 12 22 32)。然后:- 向量中的第一项(即向量[1])是线性化矩阵中的第二项- 向量中的第二项 22 是底层向量中的第 6 个元素- 向量中的第三项 32 是v_的第 10 个元素

现在,用铅笔和纸对矩阵的第三列(元素 13 23 33)执行相同的操作。查看第二列的基础向量中的索引(分别为 2、6 和 10)与第三列的索引之间是否存在任何相似之处。