Как перемещаться по вектору с помощью итераторов? (С++)
Целью является доступ к "n-му" элементу вектора строк вместо оператора [] или "at". Насколько я понимаю, итераторы могут использоваться для навигации по контейнерам, но я никогда не использовал итераторы раньше, и то, что я читаю, путается.
Если бы кто-нибудь мог дать мне некоторую информацию о том, как этого добиться, я был бы признателен. Спасибо.
Ответы
Ответ 1
Вам нужно использовать begin
и end
класса vector
, который возвращает итератор, ссылаясь на первый и последний элементы соответственно.
using namespace std;
vector<string> myvector; // a vector of stings.
// push some strings in the vector.
myvector.push_back("a");
myvector.push_back("b");
myvector.push_back("c");
myvector.push_back("d");
vector<string>::iterator it; // declare an iterator to a vector of strings
int n = 3; // nth element to be found.
int i = 0; // counter.
// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ ) {
// found nth element..print and break.
if(i == n) {
cout<< *it << endl; // prints d.
break;
}
}
// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl; // prints d.
// using the at method
cout << myvector.at(n) << endl; // prints d.
Ответ 2
Как правило, итераторы используются для доступа к элементам контейнера линейно; однако, с "итераторами произвольного доступа", можно получить доступ к любому элементу таким же образом, как operator[]
.
Чтобы получить доступ к произвольным элементам в векторе vec
, вы можете использовать следующее:
vec.begin() // 1st
vec.begin()+1 // 2nd
// ...
vec.begin()+(i-1) // ith
// ...
vec.begin()+(vec.size()-1) // last
Ниже приведен пример типичного шаблона доступа (более ранние версии С++):
int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
Преимущество использования итератора заключается в том, что вы можете применить тот же шаблон к другим контейнерам:
sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
sum += *it;
}
По этой причине очень легко создать шаблон кода, который будет работать с тем же , независимо от типа контейнера.
Другим преимуществом итераторов является то, что он не предполагает, что данные хранятся в памяти; например, можно создать передовой итератор, который может считывать данные из входного потока или просто генерировать данные "на лету" (например, генератор диапазона или генератора случайных чисел).
Другой вариант с использованием std::for_each
и lambdas:
sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });
С С++ 11 вы можете использовать auto
, чтобы избежать указания очень длинного и сложного имени типа итератора, как было показано ранее (или даже более сложного):
sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
И, кроме того, для каждого варианта есть более простой вариант:
sum = 0;
for (auto value : vec) {
sum += value;
}
И, наконец, есть также std::accumulate
, где вы должны быть осторожны, добавляете ли вы числа целых чисел или чисел с плавающей запятой.
Ответ 3
Итераторы векторов - это итераторы произвольного доступа, что означает, что они выглядят и выглядят как простые указатели.
Вы можете получить доступ к n-му элементу, добавив n к итератору, возвращаемому из метода контейнера begin()
, или вы можете использовать оператор []
.
std::vector<int> vec(10);
std::Vector<int>::iterator it = vec.begin();
int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];
В качестве альтернативы вы можете использовать функцию advance, которая работает со всеми типами итераторов. (Вам нужно будет подумать, действительно ли вы хотите выполнить "произвольный доступ" с итераторами неслучайного доступа, поскольку это может быть дорогостоящим делом.)
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
std::advance(it, 5);
int sixth = *it;