cpp

vectors

01_vectors.cpp⚙️
/**
 * ============================================================
 * C++ VECTORS (std::vector)
 * ============================================================
 * 
 * This file covers:
 * - Vector basics
 * - Adding and removing elements
 * - Capacity and size
 * - Iterators
 * - Vector algorithms
 * - 2D vectors
 * 
 * Compile: g++ -std=c++17 -Wall 01_vectors.cpp -o vectors
 * Run: ./vectors
 * 
 * ============================================================
 */

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>    // For accumulate
#include <string>
#include <iomanip>

using namespace std;

// Helper function to print vectors
template<typename T>
void printVector(const vector<T>& vec, const string& label = "") {
    if (!label.empty()) cout << label << ": ";
    cout << "[";
    for (size_t i = 0; i < vec.size(); i++) {
        cout << vec[i];
        if (i < vec.size() - 1) cout << ", ";
    }
    cout << "]" << endl;
}

int main() {
    cout << "============================================" << endl;
    cout << "     C++ VECTORS" << endl;
    cout << "============================================" << endl << endl;

    // ========================================================
    // PART 1: VECTOR CREATION AND INITIALIZATION
    // ========================================================
    
    cout << "--- PART 1: CREATION & INITIALIZATION ---" << endl << endl;
    
    // Empty vector
    vector<int> empty;
    
    // Vector with initial size (elements initialized to 0)
    vector<int> sized(5);
    
    // Vector with size and initial value
    vector<int> filled(5, 10);  // Five 10s
    
    // Initialization list
    vector<int> numbers = {1, 2, 3, 4, 5};
    vector<string> fruits = {"apple", "banana", "cherry"};
    
    // Copy constructor
    vector<int> copy1(numbers);
    
    // From array
    int arr[] = {10, 20, 30, 40, 50};
    vector<int> fromArray(arr, arr + 5);
    
    // Range initialization
    vector<int> range(numbers.begin() + 1, numbers.end() - 1);  // {2, 3, 4}
    
    // Display
    printVector(empty, "empty");
    printVector(sized, "sized(5)");
    printVector(filled, "filled(5, 10)");
    printVector(numbers, "numbers");
    printVector(fruits, "fruits");
    printVector(range, "range");
    
    cout << endl;

    // ========================================================
    // PART 2: ACCESSING ELEMENTS
    // ========================================================
    
    cout << "--- PART 2: ACCESSING ELEMENTS ---" << endl << endl;
    
    vector<int> v = {10, 20, 30, 40, 50};
    
    // Using [] operator (no bounds checking)
    cout << "v[0] = " << v[0] << endl;
    cout << "v[2] = " << v[2] << endl;
    
    // Using at() (with bounds checking - throws exception)
    cout << "v.at(1) = " << v.at(1) << endl;
    
    // Front and back
    cout << "v.front() = " << v.front() << endl;
    cout << "v.back() = " << v.back() << endl;
    
    // Data pointer (access underlying array)
    int* ptr = v.data();
    cout << "*(v.data()) = " << *ptr << endl;
    cout << "*(v.data() + 2) = " << *(ptr + 2) << endl;
    
    // Modify elements
    v[0] = 100;
    v.at(1) = 200;
    printVector(v, "After modification");
    
    // ⚠️ Bounds checking example
    try {
        cout << v.at(10) << endl;  // Throws out_of_range
    } catch (const out_of_range& e) {
        cout << "Exception: " << e.what() << endl;
    }
    
    cout << endl;

    // ========================================================
    // PART 3: SIZE AND CAPACITY
    // ========================================================
    
    cout << "--- PART 3: SIZE AND CAPACITY ---" << endl << endl;
    
    vector<int> vec;
    
    cout << "Empty vector:" << endl;
    cout << "  size(): " << vec.size() << endl;
    cout << "  capacity(): " << vec.capacity() << endl;
    cout << "  empty(): " << boolalpha << vec.empty() << endl;
    cout << "  max_size(): " << vec.max_size() << endl;
    
    // Add elements and watch capacity grow
    cout << "\nAdding elements:" << endl;
    for (int i = 1; i <= 10; i++) {
        vec.push_back(i);
        cout << "  After adding " << i << ": size=" << vec.size() 
             << ", capacity=" << vec.capacity() << endl;
    }
    
    // Reserve capacity (avoid reallocations)
    vector<int> reserved;
    reserved.reserve(100);  // Pre-allocate space
    cout << "\nAfter reserve(100):" << endl;
    cout << "  size(): " << reserved.size() << endl;
    cout << "  capacity(): " << reserved.capacity() << endl;
    
    // Resize
    vector<int> resized(5, 1);
    printVector(resized, "Original");
    
    resized.resize(8, 0);  // Expand with 0s
    printVector(resized, "After resize(8, 0)");
    
    resized.resize(3);  // Shrink
    printVector(resized, "After resize(3)");
    
    // Shrink capacity to fit size
    vector<int> bloated(100);
    bloated.resize(5);
    cout << "\nBefore shrink_to_fit: capacity=" << bloated.capacity() << endl;
    bloated.shrink_to_fit();
    cout << "After shrink_to_fit: capacity=" << bloated.capacity() << endl;
    
    cout << noboolalpha << endl;

    // ========================================================
    // PART 4: ADDING AND REMOVING ELEMENTS
    // ========================================================
    
    cout << "--- PART 4: MODIFYING VECTORS ---" << endl << endl;
    
    vector<int> data = {1, 2, 3};
    printVector(data, "Initial");
    
    // push_back - add to end
    data.push_back(4);
    data.push_back(5);
    printVector(data, "After push_back(4, 5)");
    
    // emplace_back - construct in place (more efficient)
    data.emplace_back(6);
    printVector(data, "After emplace_back(6)");
    
    // pop_back - remove from end
    data.pop_back();
    printVector(data, "After pop_back()");
    
    // insert - add at position
    data.insert(data.begin() + 2, 100);  // Insert at index 2
    printVector(data, "After insert at index 2");
    
    // Insert multiple elements
    data.insert(data.end(), {7, 8, 9});
    printVector(data, "After insert {7,8,9} at end");
    
    // erase - remove at position
    data.erase(data.begin() + 2);  // Remove element at index 2
    printVector(data, "After erase at index 2");
    
    // Erase range
    data.erase(data.begin() + 4, data.end());  // Remove from index 4 to end
    printVector(data, "After erase range");
    
    // clear - remove all elements
    vector<int> toClear = {1, 2, 3};
    toClear.clear();
    cout << "After clear(): size=" << toClear.size() << endl;
    
    // assign - replace all elements
    vector<int> toAssign;
    toAssign.assign(5, 42);
    printVector(toAssign, "After assign(5, 42)");
    
    toAssign.assign({10, 20, 30});
    printVector(toAssign, "After assign({10,20,30})");
    
    cout << endl;

    // ========================================================
    // PART 5: ITERATORS
    // ========================================================
    
    cout << "--- PART 5: ITERATORS ---" << endl << endl;
    
    vector<int> nums = {10, 20, 30, 40, 50};
    
    // Using iterators
    cout << "Forward iteration: ";
    for (vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Using auto (cleaner)
    cout << "With auto: ";
    for (auto it = nums.begin(); it != nums.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Reverse iteration
    cout << "Reverse: ";
    for (auto it = nums.rbegin(); it != nums.rend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Const iterators (read-only)
    cout << "Const iterator: ";
    for (auto it = nums.cbegin(); it != nums.cend(); ++it) {
        cout << *it << " ";
        // *it = 100;  // ERROR: can't modify through const iterator
    }
    cout << endl;
    
    // Iterator arithmetic
    auto start = nums.begin();
    auto finish = nums.end();
    cout << "Distance: " << distance(start, finish) << endl;
    cout << "Third element: " << *(start + 2) << endl;
    
    // Modifying through iterator
    for (auto it = nums.begin(); it != nums.end(); ++it) {
        *it *= 2;
    }
    printVector(nums, "After doubling");
    
    cout << endl;

    // ========================================================
    // PART 6: ALGORITHMS WITH VECTORS
    // ========================================================
    
    cout << "--- PART 6: ALGORITHMS ---" << endl << endl;
    
    vector<int> values = {64, 34, 25, 12, 22, 11, 90};
    printVector(values, "Original");
    
    // Sort
    sort(values.begin(), values.end());
    printVector(values, "Sorted ascending");
    
    sort(values.begin(), values.end(), greater<int>());
    printVector(values, "Sorted descending");
    
    // Sort again for other algorithms
    sort(values.begin(), values.end());
    
    // Binary search (requires sorted vector)
    bool found = binary_search(values.begin(), values.end(), 25);
    cout << "binary_search(25): " << boolalpha << found << endl;
    
    // Find
    auto it = find(values.begin(), values.end(), 34);
    if (it != values.end()) {
        cout << "Found 34 at index: " << distance(values.begin(), it) << endl;
    }
    
    // Count
    values.push_back(25);
    int cnt = count(values.begin(), values.end(), 25);
    cout << "Count of 25: " << cnt << endl;
    
    // Min and Max
    auto minIt = min_element(values.begin(), values.end());
    auto maxIt = max_element(values.begin(), values.end());
    cout << "Min: " << *minIt << ", Max: " << *maxIt << endl;
    
    // Sum (accumulate)
    int sum = accumulate(values.begin(), values.end(), 0);
    cout << "Sum: " << sum << endl;
    
    // Reverse
    reverse(values.begin(), values.end());
    printVector(values, "Reversed");
    
    // Remove-erase idiom
    vector<int> withDups = {1, 2, 2, 3, 3, 3, 4};
    withDups.erase(remove(withDups.begin(), withDups.end(), 3), withDups.end());
    printVector(withDups, "After removing 3s");
    
    // Unique (remove consecutive duplicates - sort first!)
    vector<int> dups = {1, 1, 2, 2, 3, 3, 3};
    dups.erase(unique(dups.begin(), dups.end()), dups.end());
    printVector(dups, "After unique");
    
    cout << noboolalpha << endl;

    // ========================================================
    // PART 7: 2D VECTORS
    // ========================================================
    
    cout << "--- PART 7: 2D VECTORS ---" << endl << endl;
    
    // Creating 2D vector
    vector<vector<int>> matrix = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    
    // Display
    cout << "2D Vector (Matrix):" << endl;
    for (const auto& row : matrix) {
        for (int val : row) {
            cout << setw(3) << val;
        }
        cout << endl;
    }
    
    // Access elements
    cout << "matrix[1][2] = " << matrix[1][2] << endl;
    
    // Create 3x4 matrix filled with zeros
    int rows = 3, cols = 4;
    vector<vector<int>> grid(rows, vector<int>(cols, 0));
    
    cout << "\n3x4 Grid initialized to 0:" << endl;
    for (const auto& row : grid) {
        for (int val : row) {
            cout << val << " ";
        }
        cout << endl;
    }
    
    // Add row
    grid.push_back({1, 1, 1, 1});
    cout << "\nAfter adding a row:" << endl;
    for (const auto& row : grid) {
        for (int val : row) {
            cout << val << " ";
        }
        cout << endl;
    }
    
    // Jagged array (rows of different sizes)
    vector<vector<int>> jagged = {
        {1},
        {2, 3},
        {4, 5, 6},
        {7, 8, 9, 10}
    };
    
    cout << "\nJagged array:" << endl;
    for (const auto& row : jagged) {
        for (int val : row) {
            cout << val << " ";
        }
        cout << endl;
    }
    
    cout << endl;

    // ========================================================
    // PART 8: VECTOR vs ARRAY COMPARISON
    // ========================================================
    
    cout << "--- PART 8: VECTOR vs ARRAY ---" << endl << endl;
    
    cout << "┌────────────────┬───────────────┬───────────────┐" << endl;
    cout << "│ Feature        │ Array         │ Vector        │" << endl;
    cout << "├────────────────┼───────────────┼───────────────┤" << endl;
    cout << "│ Size           │ Fixed         │ Dynamic       │" << endl;
    cout << "│ Memory         │ Stack/Static  │ Heap          │" << endl;
    cout << "│ Bounds check   │ No            │ at() method   │" << endl;
    cout << "│ Size info      │ Manual        │ size()        │" << endl;
    cout << "│ Pass to func   │ Decays        │ By reference  │" << endl;
    cout << "│ Performance    │ Slightly faster│ Slight overhead│" << endl;
    cout << "└────────────────┴───────────────┴───────────────┘" << endl;
    
    cout << "\n💡 Recommendation: Use std::vector by default!" << endl;
    
    cout << endl;

    cout << "============================================" << endl;
    cout << "VECTOR SUMMARY:" << endl;
    cout << "============================================" << endl;
    cout << "• Dynamic resizing" << endl;
    cout << "• Rich API for manipulation" << endl;
    cout << "• Works with STL algorithms" << endl;
    cout << "• Bounds checking with at()" << endl;
    cout << "• Contiguous memory storage" << endl;
    cout << "============================================" << endl;

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Implement a function to remove all duplicates from a vector
 * 
 * 2. Write a program that reads numbers until -1 is entered,
 *    stores them in a vector, and displays statistics
 * 
 * 3. Implement merge sort using vectors
 * 
 * 4. Create a sparse matrix representation using 2D vectors
 * 
 * 5. Write a function to rotate a 2D vector (matrix) 90 degrees
 */
Vectors - C++ Tutorial | DeepML