Как повернуть вектор векторов - PullRequest
11 голосов
/ 15 мая 2011

Я ищу элегантный способ предварительного поворота вектора вектора с использованием алгоритмов 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 ]

9 голосов
/ 15 мая 2011

Полагаю, самое простое решение - написать простую функцию 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 или что-то в этом роде.Таким образом, транспонирование включает в себя не копирование данных, а просто изменение расчета индексов.

7 голосов
/ 15 мая 2011

Посмотрите на Boost MultiArray.Вы можете создать вложенных просмотров ваших данных.Также есть vnl_matrix , который имеет метод транспонирования.

2 голосов
/ 16 мая 2011

Я бы представил оболочку, которая конвертирует строки -> столбцы и столбцы -> строки.Это избавит вас от необходимости копировать все данные.

#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";
}
1 голос
/ 15 мая 2011

Если вы собираетесь делать много линейной алгебры в 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;
}
0 голосов
/ 15 мая 2011

Должен ли это быть вектор векторов?

Если нет, то вы, вероятно, могли бы реализовать обертку над обычным вектором строк * элементов столбцов.

Что-то вроде:

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. запишите элементы матрицы 3х4 в матричной форме

11 12 13 14 21 22 23 24 31 32 33 34

  1. написать их линеаризованным способом:

11 12 13 14 21 22 23 24 31 32 33 34

Существует простая связь между индексами элемента из матричной формы иего индекс в линеаризованной форме, который зависит от геометрии матрицы.

  1. , если вы хотите, чтобы вектор «содержал» элементы 21 22 23 24 (или 12 22 32), то вам нужно реализовать некоторую логику вваш оператор [] (int index), который будет определять индекс в базовом векторе элемента из Vector [index].

Скажем, ваш Vector должен ссылаться на второй столбец из матрицы (т.е. 1222 32).Тогда: - первый элемент в векторе (т.е. Vector [1]) является вторым элементом в линеаризованной матрице - второй элемент в векторе, 22, является 6-м элементом из базового вектора - третий элемент в векторе,32, является 10-м элементом v_

Теперь с карандашом и бумагой сделайте то же самое для третьего столбца матрицы (элементы 13, 23, 33).Посмотрите, заметили ли вы сходство между индексами в базовом векторе для второго столбца (которые были 2, 6 и 10) и индексами, которые вы найдете для третьего столбца.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...