Vector Part 2

Estimated reading: 13 minutes 130 Views

Iterators

In C++, iterators are objects that provide a way to traverse the elements of a container (such as vectors) in a sequential manner. Iterators act as pointers to elements in the container, allowing you to access and manipulate the elements efficiently. They serve as a bridge between algorithms and data structures, enabling you to perform various operations on container elements without needing to know the underlying implementation details.

For vectors specifically, iterators offer several functionalities:

  1. Accessing Elements: You can use iterators to access individual elements of a vector. Iterators support dereferencing, which allows you to retrieve the value of the element they point to.
  2. Traversal: Iterators provide mechanisms for traversing through the elements of a vector sequentially. You can increment or decrement an iterator to move to the next or previous element, respectively.
  3. Range-Based Operations: Iterators can define ranges within a vector, allowing you to perform operations on subsets of elements. For example, you can specify a range of iterators to indicate a subset of elements to sort or to copy to another container.
  4. Iterator Categories: Iterators in C++ are classified into different categories based on their capabilities and behavior. For vectors, the most commonly used iterator category is the random access iterator, which supports efficient random access to elements using arithmetic operations like addition and subtraction.
  5. Iterator Invalidation: Modifying a vector (e.g., inserting or erasing elements) can invalidate iterators pointing to elements within the vector. It’s essential to be aware of iterator invalidation rules to avoid undefined behavior when working with iterators.

Example 1:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {10, 20, 30, 40};
    vector<int>::iterator it = v.begin();
    cout << *it;
    return 0;
}

Here’s what each line of the code does:

  • vector<int> v = {10, 20, 30, 40};: Initializes a vector v with four integers {10, 20, 30, 40}.
  • vector<int>::iterator it = v.begin();: Declares an iterator it of type vector<int>::iterator and initializes it to point to the beginning of the vector v using the begin() member function.
  • cout << *it;: Dereferences the iterator it to access the value it points to (the first element of the vector) and prints it using cout.

It prints the value of the first element of the vector v, which is 10.

Example 2:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {10, 20, 30, 40};
    vector<int>::iterator it = v.end()-1;
    cout << *it;
    return 0;
}

Here’s what each line of the code does:

  • vector<int>::iterator it = v.end() – 1;: Declares an iterator it of type vector<int>::iterator and initializes it to point to the last element of the vector v by subtracting 1 from the result of the end() member function. Note that end() returns an iterator pointing to the position after the last element, so subtracting 1 points it to the last element.
  • cout << *it;: Dereferences the iterator it to access the value it points to (the last element of the vector) and prints it using cout.

It prints the value of the last element of the vector v, which is 40.

Example 3:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {10, 20, 30, 40};
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << endl;
    }
    
    return 0;
}

Here’s what each line of the code does:

  • for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { … }: This is a for loop that iterates over each element of the vector using an iterator it. It starts with the iterator it pointing to the beginning of the vector (v.begin()) and continues until the iterator is equal to v.end(), which represents one position past the end of the vector. In each iteration, the iterator is incremented to point to the next element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the iterator it to access the value of the element it points to and prints it using cout, followed by a newline (endl).

So, the output of this code will be:

10
20
30
40

Example 4:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int>v = {10, 20, 30, 40};

for (vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); it++)
{
cout << *it << endl;
}

return 0;
}

Here’s what each line of the code does:

  • for (vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); it++) { … }: This is a for loop that iterates over the vector elements in reverse order using reverse iterators. It starts with the reverse iterator it pointing to the last element of the vector (v.rbegin()) and continues until the reverse iterator reaches the position before the first element (v.rend()), exclusive. In each iteration, the reverse iterator is incremented to point to the previous element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the reverse iterator it to access the value of the element it points to and prints it using cout, followed by a newline (endl).

So, the output of this code will be:

40
30
20
10

Example 5:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {10, 20, 30, 40};
    
    for (vector<int>::const_reverse_iterator it = v.crbegin(); it != v.crend(); it++)
    {
        cout << *it << endl;
    }
    
    return 0;
}

Here’s what each line of the code does:

  • for (vector<int>::const_reverse_iterator it = v.crbegin(); it != v.crend(); it++) { … }: This is a for loop that iterates over the vector elements in reverse order using const reverse iterators. It starts with the const reverse iterator it pointing to the last element of the vector (v.crbegin()) and continues until the const reverse iterator reaches the position before the first element (v.crend()), exclusive. In each iteration, the const reverse iterator is incremented to point to the previous element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the const reverse iterator it to access the value of the element it points to and prints it using cout, followed by a newline (endl).

It prints each element of the vector v in reverse order, starting from 40 and ending with 10.

Example 6:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {10, 20, 30, 40};
    
    for (vector<int>::const_iterator it = v.cbegin(); it != v.cend(); it++)
    {
        cout << *it << endl;
    }
    
    return 0;
}

Here’s what each line of the code does:

  • for (vector<int>::const_iterator it = v.cbegin(); it != v.cend(); it++) { … }: This is a for loop that iterates over the vector elements using const iterators. It starts with the const iterator it pointing to the first element of the vector (v.cbegin()) and continues until the const iterator reaches the position after the last element (v.cend()), exclusive. In each iteration, the const iterator is incremented to point to the next element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the const iterator it to access the value of the element it points to and prints it using cout, followed by a newline (endl).

It prints each element of the vector v on a new line, iterating through the entire vector.

Auto

In C++, the auto keyword is used for type inference, allowing the compiler to automatically deduce the type of a variable based on its initializer. When used with vectors, auto can simplify code by automatically determining the correct type of iterators or elements without explicitly specifying it.

Using auto with vectors can make the code more concise and readable, especially when the iterator or element type is complex or when it’s changed frequently. However, it’s essential to use auto judiciously and ensure that the deduced type is clear and unambiguous.

Example 7:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {5, 10, 15, 20};  // Initialize vector v with four integers

    auto it = v.begin();  // Use auto to deduce the type of the iterator

    // Iterate over the vector elements using the deduced iterator type
    for (; it != v.end(); it++) {
        cout << *it << endl;  // Output the value pointed to by the iterator, followed by a newline
    }

    return 0;
}

Here’s what each line of the code does:

  • vector<int> v = {5, 10, 15, 20};: Initializes a vector v with four integers {5, 10, 15, 20}.
  • auto it = v.begin();: Uses auto to deduce the type of the iterator it. In this case, it deduces that it is of type vector<int>::iterator, pointing to the beginning of the vector v.
  • for (; it != v.end(); it++) { … }: This is a for loop that iterates over the vector elements using the deduced iterator type. It starts with the iterator it pointing to the beginning of the vector (v.begin()) and continues until the iterator reaches the position after the last element (v.end()), exclusive. In each iteration, the iterator is incremented to point to the next element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the iterator it to access the value of the element it points to and prints it using cout, followed by a newline (endl).

So, the output of this code will be:

5
10
15
20

Example 8:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {5, 10, 15, 20};
    v.insert(v.begin()+1, 12);
    v.insert(v.end()-1, 17);
    
    for (auto it = v.begin(); it != v.end(); it++)
        cout << *it << endl;
    
    return 0;
}

Here’s what each part of the code does:

  • v.insert(v.begin() + 1, 12);: Inserts the value 12 into the vector v at the position after the first element (index 1).
  • v.insert(v.end() – 1, 17);: Inserts the value 17 into the vector v at the position before the last element. Since v.end() points to one past the last element, subtracting 1 positions the insertion point before the last element.
  • for (auto it = v.begin(); it != v.end(); it++) { … }: This is a for loop that iterates over the vector elements using auto for type inference. It starts with the iterator it pointing to the beginning of the vector (v.begin()) and continues until the iterator reaches the position after the last element (v.end()), exclusive. In each iteration, the iterator is incremented to point to the next element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the iterator it to access the value of the element it points to and prints it using cout, followed by a newline (endl).

So, the output of this code will be:

5
12
10
15
17
20

Example 9:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {5, 10, 15, 20};
    v.erase(v.begin());
    
    
    for (auto it = v.begin(); it != v.end(); it++)
        cout << *it << endl;
    
    return 0;
}

Here’s what each part of the code does:

  • v.erase(v.begin());: Removes the first element from the vector v using the erase() method. Since v.begin() points to the first element, this operation removes that element from the vector.
  • for (auto it = v.begin(); it != v.end(); it++) { … }: This is a for loop that iterates over the vector elements using auto for type inference. It starts with the iterator it pointing to the beginning of the modified vector (v.begin()) and continues until the iterator reaches the position after the last element (v.end()), exclusive. In each iteration, the iterator is incremented to point to the next element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the iterator it to access the value of the element it points to and prints it using cout, followed by a newline (endl).

So, the output of this code will be:

10
15
20

Example 10:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v = {5, 10, 15, 20};
    v.erase(v.begin()+1, v.end());
    
    
    for (auto it = v.begin(); it != v.end(); it++)
        cout << *it << endl;
    
    return 0;
}

Here’s what each part of the code does:

  • v.erase(v.begin() + 1, v.end());: Removes elements from the second element (index 1) until the end of the vector using the erase() method with iterators defining the range. The range is specified from v.begin() + 1 (the iterator pointing to the second element) to v.end() (the iterator pointing one past the last element).
  • for (auto it = v.begin(); it != v.end(); it++) { … }: This is a for loop that iterates over the remaining vector elements using auto for type inference. It starts with the iterator it pointing to the beginning of the modified vector (v.begin()) and continues until the iterator reaches the position after the last remaining element (v.end()), exclusive. In each iteration, the iterator is incremented to point to the next element (it++).
  • cout << *it << endl;: Within the loop, it dereferences the iterator it to access the value of the remaining element it points to and prints it using cout, followed by a newline (endl).

So, the output of this code will be:

5

Example 11:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>v(10);
    
    for (int i = 0; i <10; i++)
        v[i] = i;
    
    cout << "Vector size initially: " << v.size();
    cout << "\nVector elemens are: ";
    for (int i = 0; i <10; i++)
        cout << v[i] << " ";
        
    v.resize(5);
    cout << "\n\nVector size after resize(5): " << v.size();
    v.shrink_to_fit();
    return 0;
}

Here’s what each part of the code does:

  • vector<int> v(10);: Initializes a vector v with size 10, containing default-initialized elements (all elements are initialized to zero in this case).
  • Assigns values to the elements of the vector using a loop.
  • Outputs the initial size of the vector using v.size().
  • Outputs the elements of the vector using a loop.
  • Resizes the vector to size 5 using v.resize(5). This operation reduces the size of the vector to 5, and any excess elements are removed from the vector.
  • Outputs the size of the vector after resizing.
  • Calls v.shrink_to_fit() to reduce the capacity of the vector to match its size.

Note: shrink_to_fit() is a non-binding request to reduce the capacity of the vector to fit its size but does not guarantee that the capacity will actually be reduced. The implementation may choose to ignore the request.

 

Share this

Vector Part 2

Or copy link

CONTENTS
English