cpp

iterators

01_iterators.cpp⚙️
/**
 * ============================================================
 * C++ STL ITERATORS
 * ============================================================
 * 
 * This file covers:
 * - Iterator categories
 * - Iterator operations
 * - Const and reverse iterators
 * - Iterator adaptors
 * - Custom iterators
 * - Modern range-based iteration
 * 
 * Compile: g++ -std=c++17 -Wall 01_iterators.cpp -o iterators
 * Run: ./iterators
 * 
 * ============================================================
 */

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <set>
#include <map>
#include <array>
#include <forward_list>
#include <iterator>
#include <algorithm>
#include <numeric>

using namespace std;

// ============================================================
// MAIN FUNCTION
// ============================================================

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

    // ========================================================
    // PART 1: ITERATOR BASICS
    // ========================================================
    
    cout << "--- PART 1: ITERATOR BASICS ---" << endl << endl;
    
    vector<int> vec = {10, 20, 30, 40, 50};
    
    // Using begin() and end()
    cout << "Forward iteration with begin()/end():" << endl;
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " ";  // Dereference to get value
    }
    cout << endl;
    
    // Using auto (preferred)
    cout << "Using auto:" << endl;
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Modifying through iterator
    cout << "Doubling values through iterator:" << endl;
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        *it *= 2;  // Modify through iterator
    }
    for (int x : vec) cout << x << " ";
    cout << endl;
    
    cout << endl;

    // ========================================================
    // PART 2: ITERATOR CATEGORIES
    // ========================================================
    
    cout << "--- PART 2: ITERATOR CATEGORIES ---" << endl << endl;
    
    cout << "Iterator Hierarchy (most to least capable):" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "1. Random Access: vector, deque, array, string" << endl;
    cout << "   - Can jump anywhere: it + n, it - n, it[n]" << endl;
    cout << "   - Can compare: it1 < it2, it1 - it2" << endl;
    cout << endl;
    
    cout << "2. Bidirectional: list, set, map" << endl;
    cout << "   - Can go forward and backward: ++it, --it" << endl;
    cout << endl;
    
    cout << "3. Forward: forward_list, unordered_set/map" << endl;
    cout << "   - Can only go forward: ++it" << endl;
    cout << endl;
    
    cout << "4. Input: istream_iterator" << endl;
    cout << "   - Read-only, single pass" << endl;
    cout << endl;
    
    cout << "5. Output: ostream_iterator" << endl;
    cout << "   - Write-only, single pass" << endl;
    
    cout << endl;
    
    // Demonstrating random access
    cout << "Random Access Iterator (vector):" << endl;
    vector<int> v = {1, 2, 3, 4, 5};
    auto it = v.begin();
    cout << "it + 2 = " << *(it + 2) << endl;
    cout << "it[3] = " << it[3] << endl;
    cout << "(v.end() - v.begin()) = " << (v.end() - v.begin()) << endl;
    
    // Bidirectional - no random access
    cout << "\nBidirectional Iterator (list):" << endl;
    list<int> lst = {1, 2, 3, 4, 5};
    auto lit = lst.begin();
    ++lit; ++lit;  // Move forward
    cout << "After ++it twice: " << *lit << endl;
    --lit;         // Move backward
    cout << "After --it: " << *lit << endl;
    // lit + 2;    // ERROR: not random access
    
    cout << endl;

    // ========================================================
    // PART 3: CONST ITERATORS
    // ========================================================
    
    cout << "--- PART 3: CONST ITERATORS ---" << endl << endl;
    
    vector<int> nums = {1, 2, 3, 4, 5};
    
    // Regular iterator - can modify
    cout << "Regular iterator (can modify):" << endl;
    for (auto it = nums.begin(); it != nums.end(); ++it) {
        *it += 10;  // OK
    }
    for (int x : nums) cout << x << " ";
    cout << endl;
    
    // Const iterator - read only
    cout << "\nConst iterator (read only):" << endl;
    for (auto it = nums.cbegin(); it != nums.cend(); ++it) {
        cout << *it << " ";
        // *it = 0;  // ERROR: cannot modify through const_iterator
    }
    cout << endl;
    
    // On const container
    const vector<int> constVec = {100, 200, 300};
    cout << "\nIterating const container:" << endl;
    for (auto it = constVec.begin(); it != constVec.end(); ++it) {
        cout << *it << " ";  // begin() returns const_iterator for const container
    }
    cout << endl;
    
    cout << endl;

    // ========================================================
    // PART 4: REVERSE ITERATORS
    // ========================================================
    
    cout << "--- PART 4: REVERSE ITERATORS ---" << endl << endl;
    
    vector<int> data = {1, 2, 3, 4, 5};
    
    cout << "Forward: ";
    for (auto it = data.begin(); it != data.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    cout << "Reverse: ";
    for (auto it = data.rbegin(); it != data.rend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Const reverse
    cout << "Const reverse: ";
    for (auto it = data.crbegin(); it != data.crend(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Converting reverse to forward iterator
    auto rit = data.rbegin();
    ++rit; ++rit;  // Points to 3 in reverse (element 2 from end)
    auto fwd = rit.base();  // Convert to forward iterator (points to 4)
    cout << "\nReverse iterator at 3, base() gives: " << *fwd << endl;
    
    cout << endl;

    // ========================================================
    // PART 5: ITERATOR OPERATIONS
    // ========================================================
    
    cout << "--- PART 5: ITERATOR OPERATIONS ---" << endl << endl;
    
    vector<int> ops = {10, 20, 30, 40, 50, 60, 70, 80, 90};
    
    auto first = ops.begin();
    auto last = ops.end();
    
    // advance - moves iterator
    cout << "advance(it, 3): ";
    auto it1 = first;
    advance(it1, 3);
    cout << *it1 << endl;
    
    // distance - counts elements between iterators
    cout << "distance(begin, end): " << distance(first, last) << endl;
    
    // next/prev - return new iterator
    auto it2 = next(first, 2);
    cout << "next(begin, 2): " << *it2 << endl;
    
    auto it3 = prev(last, 3);
    cout << "prev(end, 3): " << *it3 << endl;
    
    // For bidirectional iterators
    list<int> myList = {1, 2, 3, 4, 5};
    auto lit2 = myList.begin();
    advance(lit2, 2);  // Works on bidirectional
    cout << "\nadvance on list: " << *lit2 << endl;
    
    cout << endl;

    // ========================================================
    // PART 6: INSERT ITERATORS
    // ========================================================
    
    cout << "--- PART 6: INSERT ITERATORS ---" << endl << endl;
    
    vector<int> src = {1, 2, 3, 4, 5};
    vector<int> dest;
    
    // back_inserter - inserts at back
    cout << "back_inserter:" << endl;
    copy(src.begin(), src.end(), back_inserter(dest));
    for (int x : dest) cout << x << " ";
    cout << endl;
    
    // front_inserter - inserts at front (requires push_front)
    cout << "\nfront_inserter (deque):" << endl;
    deque<int> dq;
    copy(src.begin(), src.end(), front_inserter(dq));
    for (int x : dq) cout << x << " ";  // Reversed!
    cout << endl;
    
    // inserter - inserts at specific position
    cout << "\ninserter at middle:" << endl;
    vector<int> mid = {100, 200};
    auto midIt = mid.begin() + 1;  // After 100
    copy(src.begin(), src.end(), inserter(mid, midIt));
    for (int x : mid) cout << x << " ";
    cout << endl;
    
    cout << endl;

    // ========================================================
    // PART 7: STREAM ITERATORS
    // ========================================================
    
    cout << "--- PART 7: STREAM ITERATORS ---" << endl << endl;
    
    // ostream_iterator - output
    cout << "Using ostream_iterator:" << endl;
    vector<int> output = {1, 2, 3, 4, 5};
    copy(output.begin(), output.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    
    cout << "With different delimiter:" << endl;
    copy(output.begin(), output.end(), ostream_iterator<int>(cout, ", "));
    cout << endl;
    
    // istream_iterator example (commented - would wait for input)
    // cout << "Enter integers (Ctrl+D to end):" << endl;
    // vector<int> input(istream_iterator<int>(cin), istream_iterator<int>());
    
    cout << endl;

    // ========================================================
    // PART 8: ITERATOR WITH ALGORITHMS
    // ========================================================
    
    cout << "--- PART 8: ITERATORS WITH ALGORITHMS ---" << endl << endl;
    
    vector<int> alg = {5, 2, 8, 1, 9, 3, 7, 4, 6};
    
    // find
    auto found = find(alg.begin(), alg.end(), 8);
    if (found != alg.end()) {
        cout << "Found 8 at position: " << distance(alg.begin(), found) << endl;
    }
    
    // find_if
    auto evenIt = find_if(alg.begin(), alg.end(), [](int x) { return x % 2 == 0; });
    cout << "First even: " << *evenIt << endl;
    
    // count
    cout << "Count of elements > 5: " 
         << count_if(alg.begin(), alg.end(), [](int x) { return x > 5; }) << endl;
    
    // sort
    sort(alg.begin(), alg.end());
    cout << "Sorted: ";
    for (int x : alg) cout << x << " ";
    cout << endl;
    
    // binary_search (requires sorted)
    cout << "binary_search(6): " << (binary_search(alg.begin(), alg.end(), 6) ? "found" : "not found") << endl;
    
    // lower_bound/upper_bound
    auto lb = lower_bound(alg.begin(), alg.end(), 5);
    auto ub = upper_bound(alg.begin(), alg.end(), 5);
    cout << "lower_bound(5) at index: " << distance(alg.begin(), lb) << endl;
    cout << "upper_bound(5) at index: " << distance(alg.begin(), ub) << endl;
    
    // accumulate
    int sum = accumulate(alg.begin(), alg.end(), 0);
    cout << "Sum: " << sum << endl;
    
    cout << endl;

    // ========================================================
    // PART 9: MAP ITERATORS
    // ========================================================
    
    cout << "--- PART 9: MAP ITERATORS ---" << endl << endl;
    
    map<string, int> scores = {
        {"Alice", 95},
        {"Bob", 87},
        {"Charlie", 92}
    };
    
    // Iterating map
    cout << "Map iteration:" << endl;
    for (auto it = scores.begin(); it != scores.end(); ++it) {
        cout << "  " << it->first << ": " << it->second << endl;
    }
    
    // Structured bindings (C++17)
    cout << "\nWith structured bindings:" << endl;
    for (const auto& [name, score] : scores) {
        cout << "  " << name << ": " << score << endl;
    }
    
    // Finding in map
    auto mapIt = scores.find("Bob");
    if (mapIt != scores.end()) {
        cout << "\nFound Bob with score: " << mapIt->second << endl;
    }
    
    cout << endl;

    // ========================================================
    // ITERATOR SUMMARY
    // ========================================================
    
    cout << "--- ITERATOR SUMMARY ---" << endl << endl;
    
    cout << "Iterator Types:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "iterator         - Read/write forward" << endl;
    cout << "const_iterator   - Read-only forward" << endl;
    cout << "reverse_iterator - Read/write backward" << endl;
    cout << "const_reverse_iterator - Read-only backward" << endl;
    
    cout << "\nObtaining Iterators:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "begin()/end()     - Forward iterators" << endl;
    cout << "cbegin()/cend()   - Const forward" << endl;
    cout << "rbegin()/rend()   - Reverse iterators" << endl;
    cout << "crbegin()/crend() - Const reverse" << endl;
    
    cout << "\nIterator Operations:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "advance(it, n)    - Move iterator n steps" << endl;
    cout << "distance(it1,it2) - Count steps between" << endl;
    cout << "next(it, n)       - Return iterator n ahead" << endl;
    cout << "prev(it, n)       - Return iterator n behind" << endl;
    
    cout << endl;

    cout << "============================================" << endl;
    cout << "STL ITERATORS COMPLETE!" << endl;
    cout << "============================================" << endl;

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Create a function that:
 *    - Takes two iterators (any container)
 *    - Returns iterator to the middle element
 *    - Handle even/odd sizes
 * 
 * 2. Implement a range class:
 *    - range(start, end, step)
 *    - Support begin()/end() for range-based for
 *    - Lazy evaluation (doesn't store values)
 * 
 * 3. Create a filter iterator:
 *    - Wraps another iterator
 *    - Only yields elements matching predicate
 *    - Implement ++, *, ==, !=
 * 
 * 4. Implement merge using iterators:
 *    - Take two sorted ranges
 *    - Output merged sorted sequence
 *    - Use only iterator operations
 */
Iterators - C++ Tutorial | DeepML