Итератор для 2d-вектора
Как создать итератор для sd-вектора (вектор векторов)?
Ответы
Ответ 1
Хотя ваш вопрос не очень ясен, я собираюсь предположить, что вы имеете в виду, что 2D-вектор означает вектор векторов:
vector< vector<int> > vvi;
Затем вам нужно использовать два итератора, чтобы пересечь его, первый итератор "строк", второй - итераторы "столбцов" в этой "строке":
//assuming you have a "2D" vector vvi (vector of vector of int's)
vector< vector<int> >::iterator row;
vector<int>::iterator col;
for (row = vvi.begin(); row != vvi.end(); row++) {
for (col = row->begin(); col != row->end(); col++) {
// do stuff ...
}
}
Ответ 2
Вы можете использовать оператор range для выражения для итерации всех элементов в двумерном векторе.
vector< vector<int> > vec;
И пусть предположим, что вы уже push_back много элементов в vec;
for(auto& row:vec){
for(auto& col:row){
//do something using the element col
}
}
Ответ 3
Другой способ интерпретировать этот вопрос состоит в том, что вам нужен 1D-итератор над vector<vector<>>
, например, для подачи его на for_each()
или какой-либо другой алгоритм.
Вы можете сделать это вот так:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
// An iterator over a vector of vectors.
template<typename T>
class vv_iterator : public std::iterator<std::bidirectional_iterator_tag, T>{
public:
static vv_iterator<T> begin(std::vector<std::vector<T>>& vv) {
return vv_iterator(&vv, 0, 0);
}
static vv_iterator<T> end(std::vector<std::vector<T>>& vv) {
return vv_iterator(&vv, vv.size(), 0);
}
vv_iterator() = default;
// ++prefix operator
vv_iterator& operator++()
{
// If we haven't reached the end of this sub-vector.
if (idxInner + 1 < (*vv)[idxOuter].size())
{
// Go to the next element.
++idxInner;
}
else
{
// Otherwise skip to the next sub-vector, and keep skipping over empty
// ones until we reach a non-empty one or the end.
do
{
++idxOuter;
} while (idxOuter < (*vv).size() && (*vv)[idxOuter].empty());
// Go to the start of this vector.
idxInner = 0;
}
return *this;
}
// --prefix operator
vv_iterator& operator--()
{
// If we haven't reached the start of this sub-vector.
if (idxInner > 0)
{
// Go to the previous element.
--idxInner;
}
else
{
// Otherwise skip to the previous sub-vector, and keep skipping over empty
// ones until we reach a non-empty one.
do
{
--idxOuter;
} while ((*vv)[idxOuter].empty());
// Go to the end of this vector.
idxInner = (*vv)[idxOuter].size() - 1;
}
return *this;
}
// postfix++ operator
vv_iterator operator++(int)
{
T retval = *this;
++(*this);
return retval;
}
// postfix-- operator
vv_iterator operator--(int)
{
T retval = *this;
--(*this);
return retval;
}
bool operator==(const vv_iterator& other) const
{
return other.vv == vv && other.idxOuter == idxOuter && other.idxInner == idxInner;
}
bool operator!=(const vv_iterator &other) const
{
return !(*this == other);
}
const T& operator*() const
{
return *this;
}
T& operator*()
{
return (*vv)[idxOuter][idxInner];
}
const T& operator->() const
{
return *this;
}
T& operator->()
{
return *this;
}
private:
vv_iterator(std::vector<std::vector<T>>* _vv,
std::size_t _idxOuter,
std::size_t _idxInner)
: vv(_vv), idxOuter(_idxOuter), idxInner(_idxInner) {}
std::vector<std::vector<int>>* vv = nullptr;
std::size_t idxOuter = 0;
std::size_t idxInner = 0;
};
int main()
{
std::vector<std::vector<int>> a = {{3, 5, 2, 6}, {-1, -4, -3, -5}, {100}, {-100}};
std::reverse(vv_iterator<int>::begin(a), vv_iterator<int>::end(a));
for (const auto& v : a)
{
std::cout << "{ ";
for (auto i : v)
std::cout << i << " ";
std::cout << "}\n";
}
}
Печать
{ -100 100 -5 -3 }
{ -4 -1 6 2 }
{ 5 }
{ 3 }
Примечание. Это не будет работать с std::sort()
, потому что для этого требуется итератор с произвольным доступом. Вы можете сделать это итератором с произвольным доступом, но вам придется сканировать вектор в начале, чтобы вы могли отображать от плоского индекса до idxOuter
и idxInner
в постоянное время. Не совсем тривиально, но не сложно.
Ответ 4
Предполагая, что вы имеете в виду итератор STL, и пользовательский контейнер, который реализует общий 2D-массив объектов, это невозможно. Итераторы STL поддерживают только приращение и уменьшение (т.е. "Следующие" "предыдущие" ) операции, при которых движение через 2D-набор требует четырех таких примитивов (например, влево/вправо/вверх/вниз и т.д.). Метафоры не совпадают.
Что вы пытаетесь сделать?
Ответ 5
Предполагая, что вы имеете в виду вектор векторов, и у вас есть std::vector
, нет встроенного способа сделать это, поскольку итераторы поддерживают только операции увеличения и уменьшения для перемещения вперед и назад.
2D-вектор - это матрица, поэтому вам нужны два типа итератора: итератор строк и итератор столбца. Итераторы строк будут перемещать "вверх" и "вниз" по матрице, тогда как итераторы столбцов будут перемещаться "влево" и "вправо".
Вы должны сами реализовать эти классы итераторов, что не обязательно тривиально. Если, конечно, вы просто не хотите перебирать каждый слот в матрице, в этом случае двойной цикл, использующий индексные переменные i
и j
, будет работать нормально. В зависимости от ваших потребностей (ваш пост здесь немного отсутствует в содержимом), вы можете использовать boost::numeric::ublas::matrix
, который является матричным классом из библиотеки линейной алгебры Boost. Этот матричный класс имеет встроенные итераторы строк и столбцов, которые упрощают итерацию по матрице.
Ответ 6
Предположим, у вас есть такой вектор:
vector <vector<int>> vect{{1,2,3},{4,5,6},{7,8,9}};
Теперь для использования итераторов с 2D векторами:
for(auto i = vect.begin() ; i<vect.end() ; i++)
{
for(auto j = i->begin() ; j<i->end() ; j++)
cout << *j <<" ";
cout <<"\n";
//similarly you can do other things
}
Также другой более короткий путь
for(auto i : vect)
{
for(auto j : i)
cout << j <<" ";
cout << "\n";
//similarly you can do other things also.
}
Обратите внимание, что способ вызова переменных различен в обоих случаях.