Iterators are one of the four pillars of the STL. They are very similar to pointers. Like pointers point to the memory address of the variable, iterators point to the memory locations of the elements of the STL containers.
They allow us to access the elements of the container. They reduce the complexity and execution time of the program. Algorithms in STL manipulate data using iterators. The type of container doesn't matter while using iterators, thus making it generic.
Declaring an iterator
Syntax:
container_type::iterator iterator_name;Example:
vector < int > v;
vector < int > ::iterator itr; //creates an iterator itr to a vector of integersTypes of Iterators
According to functionality, iterators can be classified into five types. Let us discuss them one by one:
- Input Iterators: They are the least commonly used iterators and are mainly used for reading values from the container. They allow us to sequentially visit the data, such that no element can be accessed more than once. They don't allow us to modify the values of the container.
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector < int > v = { 1, 2, 3, 4, 5 };
vector < int > ::iterator itr;
for (itr = v.begin(); itr != v.end(); ++itr) {
cout << ( * itr) << " ";
}
return 0;
}Output
1 2 3 4 5 2. Output iterators: They are the exact opposite of the output iterators. Just like input containers are used to read the elements of the container, output iterators are used to modify them. They are also a one-way iterator.
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector < int > v = { 1, 2, 3, 4, 5 };
vector < int > ::iterator itr;
for (itr = v.begin(); itr != v.end(); ++itr) {
* itr = 100;
}
return 0;
}3. Forward iterators: They are a combination of input and output iterators. They allow us both to access and modify the values of the container. Also, we can traverse the container only in the forward direction.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector < int > v = { 1, 2, 3, 4, 5 };
vector < int > ::iterator itr;
for (itr = v.begin(); itr != v.end(); ++itr) {
* itr = * itr + 10;
}
for (itr = v.begin(); itr != v.end(); ++itr) {
cout << ( * itr) << " ";
}
return 0;
}Output
11 12 13 14 15 4. Bidirectional iterators: They are a replica of the forward iterators except for the fact that they allow us to move in both directions i.e support decrement operator.
#include<iostream>
#include<list>
using namespace std;
int main() {
list < int > l = { 1, 2, 3, 4, 5 };
list < int > ::iterator itr;
for (itr = l.end(); itr != l.begin(); --itr) {
if (itr != l.end()) {
cout << ( * itr) << " ";
}
}
cout << ( * itr);
return 0;
}Output
5 4 3 2 15. Random-Access Iterators: They provide us random access to the elements of the container. They are also called bi-directional with random access.
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector < int > v = { 1, 2, 3, 4, 5 };
vector < int > ::iterator itr1;
vector < int > ::iterator itr2;
itr1 = v.begin();
itr2 = v.end();
if (itr1 < itr2) {
cout << "Moving from begin to end\n";
cout << "The number of elements are " << itr2 - itr1;
}
return 0;
}Output
Moving from begin to end
The number of elements are 5Operations on Iterators
begin(): It returns a bidirectional iterator pointing to the first element of the container.
Parameters: None
Return value: iterator
end(): It returns a bidirectional iterator pointing past the last element of the container.
Parameters: None
Return value: iterator
advance(itr, value): It increments the iterator by a certain value.
Parameters: iterator, whose value needs to be incremented, integer value specifying by how much steps iterator should be advanced
Return value: None
next(itr, value): It returns a new iterator that the iterator would point to after advancing the iterator value times.
Parameters: iterator, whose value needs to be incremented, integer value specifying by how many steps iterator should be advanced
Return value: iterator
prev(itr, value): It returns a new iterator that the iterator would point to after decrementing the iterator value times.
Parameters: iterator, whose value needs to be decremented, integer value specifying by how many steps iterator should be decremented
Return value: iterator
inserter(container, itr): It inserts the element at any position.
Parameters: container in which element needs to be inserted, the position where element needs to be inserted
Return type: None
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector < int > v = { 1, 2, 3, 4, 5 };
vector < int > v2 = { 10, 20, 30 };
vector < int > ::iterator itr = v.begin();
cout << "The elements are: ";
for (itr = v.begin(); itr < v.end(); itr++) {
cout << * itr << ' ';
}
cout << '\n';
itr = v.begin();
advance(itr, 3);
cout << "Iterator after advancing 3 steps: ";
cout << * itr << '\n';
vector < int > ::iterator it1 = prev(itr, 2);
cout << "The position of prev iterator : ";
cout << * it1 << '\n';
vector < int > ::iterator it2 = next(itr, 1);
cout << "The position of new iterator: ";
cout << * it2 << '\n';
copy(v2.begin(), v2.end(), inserter(v, itr));
cout << "The new vector after inserting elements is : ";
for (int & it: v)
cout << it << " ";
return 0;
}Output
The elements are: 1 2 3 4 5
Iterator after advancing 3 steps: 4
The position of prev iterator : 2
The position of new iterator: 5
The new vector after inserting elements is : 1 2 3 10 20 30 4 5 Why use iterators?
- They are easy and convenient to use.
- They are generic.
- They are efficient.
- They help us to add or modify data dynamically.