Vectors

Vectors are dynamic arrays that can resize themselves automatically when elements are added or removed. They are one of the most commonly used containers in C++ and provide the flexibility of dynamic memory allocation with the performance benefits of contiguous memory storage.

The C++ Standard Template Library (STL) provides a powerful vector class that handles memory management automatically, making it safer and more convenient than manual dynamic arrays while maintaining excellent performance.

Vector Basics

Vectors can be initialized in multiple ways and support various data types:

Creating and Initializing Vectors

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

int main() {
    // Different ways to create vectors
    vector<int> numbers1;                    // Empty vector
    vector<int> numbers2(5);                 // 5 elements, all initialized to 0
    vector<int> numbers3(5, 10);             // 5 elements, all initialized to 10
    vector<int> numbers4 = {1, 2, 3, 4, 5}; // Initialize with values
    vector<int> numbers5(numbers4);          // Copy constructor
    
    // Display vector contents
    cout << "numbers1 (empty): ";
    for (int num : numbers1) cout << num << " ";
    cout << "Size: " << numbers1.size() << endl;
    
    cout << "numbers2 (5 zeros): ";
    for (int num : numbers2) cout << num << " ";
    cout << "Size: " << numbers2.size() << endl;
    
    cout << "numbers3 (5 tens): ";
    for (int num : numbers3) cout << num << " ";
    cout << "Size: " << numbers3.size() << endl;
    
    cout << "numbers4 (1-5): ";
    for (int num : numbers4) cout << num << " ";
    cout << "Size: " << numbers4.size() << endl;
    
    // Vector of strings
    vector<string> fruits = {"apple", "banana", "orange"};
    cout << "\nFruits: ";
    for (const string& fruit : fruits) {
        cout << fruit << " ";
    }
    cout << endl;
    
    return 0;
}

Adding and Removing Elements

Vectors automatically resize when needed. Common operations include push_back(), insert(), pop_back(), and erase():

Dynamic Resizing Operations

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

void printVector(const vector<int>& vec, const string& label) {
    cout << label << ": ";
    for (int val : vec) cout << val << " ";
    cout << "(size: " << vec.size() << ", capacity: " << vec.capacity() << ")" << endl;
}

int main() {
    vector<int> numbers;
    
    cout << "=== Adding Elements ===" << endl;
    printVector(numbers, "Initial");
    
    // Adding elements to the end
    numbers.push_back(10);
    printVector(numbers, "After push_back(10)");
    
    numbers.push_back(20);
    numbers.push_back(30);
    printVector(numbers, "After adding 20, 30");
    
    // Insert at specific position
    numbers.insert(numbers.begin() + 1, 15);  
    printVector(numbers, "After insert 15 at index 1");
    
    cout << "\n=== Removing Elements ===" << endl;
    
    // Remove last element
    numbers.pop_back();
    printVector(numbers, "After pop_back()");
    
    // Remove at specific position
    numbers.erase(numbers.begin() + 1);
    printVector(numbers, "After erasing index 1");
    
    // Clear all elements
    numbers.clear();
    printVector(numbers, "After clear");
    
    return 0;
}

Vector Iterators

Iterators provide a way to traverse through vector elements and are essential for many STL algorithms:

Using Iterators

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

int main() {
    vector<int> numbers = {5, 2, 8, 1, 9, 3};
    
    // Using iterators to traverse
    cout << "Forward iteration: ";
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Reverse iteration
    cout << "Reverse iteration: ";
    for (auto it = numbers.rbegin(); it != numbers.rend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Using algorithms with iterators
    sort(numbers.begin(), numbers.end());
    cout << "After sorting: ";
    for (int num : numbers) cout << num << " ";
    cout << endl;
    
    // Find element
    auto found = find(numbers.begin(), numbers.end(), 5);
    if (found != numbers.end()) {
        cout << "Found 5 at position: " << distance(numbers.begin(), found) << endl;
    }
    
    return 0;
}

Performance Considerations

Understanding vector performance characteristics helps write efficient code:

  • Random access: O(1) - accessing elements by index is constant time
  • Insertion/deletion at end: O(1) amortized - push_back and pop_back are very efficient
  • Insertion/deletion at middle: O(n) - requires shifting elements
  • Memory: Contiguous storage provides cache-friendly access patterns