如何旋转矢量矢量

时间:2011-05-15 16:44:27

标签: c++ vector

我正在寻找一种优雅的方法来使用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

5 个答案:

答案 0 :(得分:9)

我想最简单的解决方案就是编写一个简单的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, j或类似内容计算元素i*row_length + j的位置。这样,转置不涉及复制数据,只是改变索引的计算。

答案 1 :(得分:7)

看看Boost MultiArray。您可以创建sub-views数据。还有vnl_matrix,它有一个转置方法。

答案 2 :(得分:2)

我会介绍一个转换行的包装器 - &gt; col和col - &gt;行。这样可以防止您复制所有数据。

#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(TwoDWrapper& 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";
}

答案 3 :(得分:1)

如果你要在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;
}

答案 4 :(得分: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 14 21 22 23 24 31 32 33 34

  1. 以线性方式编写它们:
  2. 11 12 13 14 21 22 23 24 31 32 33 34

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

    1. 如果你想要一个Vector“包含”元素21 22 23 24(或12 22 32),那么你需要在operator [](int index)中实现一些逻辑,它将确定底层向量中的索引。来自Vector [index]的元素。
    2. 假设您的Vector需要引用矩阵中的第二列(即12 22 32)。 然后: - 向量中的第一项(即Vector [1])是线性化矩阵中的第二个元素 - 向量中的第二个项22是底层向量的第6个元素 - 向量中的第三个项目32是v _

      的第10个元素

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