итерация контейнера STL не из .begin () и его обтекание - PullRequest
10 голосов
/ 16 декабря 2011

У меня есть std :: vector, скажем, для простоты целых чисел.

std::vector<int> ivec;
ivec.push_back(1);
ivec.push_back(2);
... //omitting some push back's 3 to 99
ivec.push_back(100);

Стандартный способ итерации известен

std::map<int>::iterator it;
for( it = ivec.begin(); it != ivec.end(); it++ ) 
  print();

Эта итерация напечатает 1,2,3, ... 100.

Я хочу обойти все векторные элементы, начиная с предварительно определенного индекса, а не с него.begin (). Я хотел бы напечатать

3,4,5,6 ... 99, 100, 1, 2

Можете ли вы поделиться своими мыслями здесь?

Это может быть нормально сделать в два шага

for( it = ivec.begin()+index; it != ivec.end(); it++ ) and then (if index !=0)

for ( it = ivec.begin; it = it = ivec.begin() + (index-1); it++)

Ответы [ 6 ]

7 голосов
/ 16 декабря 2011

Вы можете либо:

  • разработать класс итератора, который обертывает vector :: iterator, и отображать поведение, которое вам нравится (в частности: ++ проверяет end (), заменяет его на begin () и корректирует другие «значения границ»)

  • заполните вектор, начиная с 3, и оберните в 100, чтобы стандартная итерация выглядела так, как вы хотите.

Выбор зависит от того, для чего еще предназначен вектор и для чего еще нужна эта итерация.

4 голосов
/ 16 декабря 2011

Я предполагаю, что у вас уже есть стартовый итератор.Как вы получите это, зависит от того, используете ли вы индексируемый (векторный) тип или только прямой итератор, или тип с ключом.Затем вы можете сделать цикл примерно так:

type::iterator start_iter = /* something from collection, perhaps begin()+index */
type::iterator cur_iter = start_iter;
do
{
  //do something with cur_iter

  ++cur_iter;
  if( cur_iter == collection.end() )
    cur_iter = collection.begin();
} while( cur_iter != start_iter );

Это основной цикл.

3 голосов
/ 16 декабря 2011
bool wrapped = false;
for (auto it = vec.begin() + index; (it != vec.begin() + index) || !wrapped; ++it)
{
    if (it == vec.end())
    {
        it = vec.begin();
        wrapped = true;
    }
    std::cout << *it;
}
2 голосов
/ 16 декабря 2011

Решение при использовании контейнера с произвольным доступом очень простое, см. Код ниже.

std::vector<int> v ({1,3,4,5,6,7,8,9,10}); /* c++11 */

...

for (int i = 2; i < (10+2); ++i)
  std::cout << v[i % 10] << " ";

Метод при использовании контейнеров, имеющих только двунаправленные и прямые итераторы:

  std::list<int> l ({1,3,4,5,6,7,8,9,10}); /* c++11 */

  Iter start = l.begin ();
  std::advance (start, 4);

  ...

  Iter it = start;

  do {
    std::cerr << *it << std::endl;

  } while (
    (it = ++it == l.end () ? l.begin () : it) != start
  );
1 голос
/ 12 февраля 2015

Я знаю, что это довольно старый вопрос, но никто не упомянул std::rotate, который, я думаю, в некоторых случаях может быть подходящим инструментом для работы.

Модифицированный пример из http://www.cplusplus.com/reference/algorithm/rotate/:

#include <iostream>     // std::cout
#include <algorithm>    // std::rotate
#include <vector>       // std::vector

int main () {
  std::vector<int> myvector;

  // set some values:
  for (int i=1; i<10; ++i) myvector.push_back(i); // 1, 2, 3, ... 9

  std::rotate(myvector.begin(),myvector.begin()+2,myvector.end());
                                                  // 3, 4, 5, 6 ... 9, 1, 2
  // print out content:
  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Выход:

myvector contains: 3 4 5 6 7 8 9 1 2

Обратите внимание, поскольку my_vector модифицируется функцией std::rotate, это не очень эффективно и не полезно, если вы просто хотите повторить вектор один раз.

Однако, хотя это, вероятно, не самый лучший ответ на этот вопрос SO, я надеюсь, что он все еще может принести некоторую пользу людям с похожими проблемами.

0 голосов
/ 16 декабря 2011

Есть бесконечные способы сделать это, и, вероятно, все (более или менее) эквивалентны, поэтому, в конце концов, это зависит от личных предпочтений и, возможно, соглашений о стиле кодирования. Я бы, наверное, сделал это так:

std::cout << v[idx] << "\n";
for( auto it = v.begin() + idx + 1; it != v.begin()+idx; ++it )
{
    if( it == v.end() ) it = v.begin();
    std::cout << *it << "\n";
}
...