STL Algorithms and Iterators

STL Algorithms and Iterators

1. Iterator

Iterators are pointer-like objects that point to container elements.

Iterator Types

Type Description Example Container
Input Iterator Read-only, one direction istream_iterator
Output Iterator Write-only, one direction ostream_iterator
Forward Iterator Read/write, one direction forward_list
Bidirectional Iterator Read/write, both directions list, set, map
Random Access Iterator All operations, random access vector, deque, array

Basic Iterator Usage

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // begin(), end()
    std::vector<int>::iterator it = v.begin();
    std::cout << *it << std::endl;  // 1

    ++it;
    std::cout << *it << std::endl;  // 2

    // Iteration
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

const Iterator

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // const_iterator: read-only
    for (std::vector<int>::const_iterator it = v.cbegin();
         it != v.cend(); ++it) {
        std::cout << *it << " ";
        // *it = 10;  // Error! Cannot modify
    }

    return 0;
}

Reverse Iterator

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // rbegin(), rend()
    for (auto it = v.rbegin(); it != v.rend(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;  // 5 4 3 2 1

    return 0;
}

2. Lambda Expressions

Defines anonymous functions concisely.

Basic Syntax

[capture](parameters) -> return_type { body }

Examples

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // Basic lambda
    auto add = [](int a, int b) {
        return a + b;
    };
    std::cout << add(3, 5) << std::endl;  // 8

    // Explicit return type
    auto divide = [](double a, double b) -> double {
        return a / b;
    };

    // With algorithms
    std::vector<int> v = {3, 1, 4, 1, 5, 9};
    std::sort(v.begin(), v.end(), [](int a, int b) {
        return a > b;  // Descending order
    });

    return 0;
}

Capture

#include <iostream>

int main() {
    int x = 10;
    int y = 20;

    // Capture by value (copy)
    auto f1 = [x]() { return x; };

    // Capture by reference
    auto f2 = [&x]() { x++; };

    // Capture all by value
    auto f3 = [=]() { return x + y; };

    // Capture all by reference
    auto f4 = [&]() { x++; y++; };

    // Mixed
    auto f5 = [=, &x]() {  // y by value, x by reference
        x++;
        return y;
    };

    f2();
    std::cout << x << std::endl;  // 11

    return 0;
}

mutable Lambda

#include <iostream>

int main() {
    int x = 10;

    // Value capture is const by default
    auto f = [x]() mutable {  // mutable allows modification
        x++;
        return x;
    };

    std::cout << f() << std::endl;  // 11
    std::cout << x << std::endl;    // 10 (original unchanged)

    return 0;
}

3. Basic Algorithms

Include the <algorithm> header.

for_each

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    std::for_each(v.begin(), v.end(), [](int n) {
        std::cout << n * 2 << " ";
    });
    std::cout << std::endl;  // 2 4 6 8 10

    return 0;
}

transform

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::vector<int> result(v.size());

    // Transform each element
    std::transform(v.begin(), v.end(), result.begin(),
                   [](int n) { return n * n; });

    for (int n : result) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 4 9 16 25

    return 0;
}

4. Search Algorithms

find

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    auto it = std::find(v.begin(), v.end(), 3);
    if (it != v.end()) {
        std::cout << "Found: " << *it << std::endl;
        std::cout << "Index: " << std::distance(v.begin(), it) << std::endl;
    }

    return 0;
}

find_if

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // First element satisfying condition
    auto it = std::find_if(v.begin(), v.end(),
                           [](int n) { return n > 3; });

    if (it != v.end()) {
        std::cout << "First > 3: " << *it << std::endl;  // 4
    }

    return 0;
}

count / count_if

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 2, 3, 2, 4, 5};

    // Count specific value
    int c1 = std::count(v.begin(), v.end(), 2);
    std::cout << "Count of 2: " << c1 << std::endl;  // 3

    // Count satisfying condition
    int c2 = std::count_if(v.begin(), v.end(),
                           [](int n) { return n % 2 == 0; });
    std::cout << "Even count: " << c2 << std::endl;  // 4

    return 0;
}

Use only on sorted ranges.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};  // Sorted

    bool found = std::binary_search(v.begin(), v.end(), 3);
    std::cout << "3 found: " << found << std::endl;  // 1

    return 0;
}

5. Sorting Algorithms

sort

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // Ascending (default)
    std::sort(v.begin(), v.end());

    // Descending
    std::sort(v.begin(), v.end(), std::greater<int>());

    // Custom comparison
    std::sort(v.begin(), v.end(), [](int a, int b) {
        return a > b;  // Descending
    });

    return 0;
}

partial_sort

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // Sort only top 3
    std::partial_sort(v.begin(), v.begin() + 3, v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    // 1 1 2 ... (only first 3 sorted)

    return 0;
}

nth_element

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // Place 3rd element in its sorted position
    std::nth_element(v.begin(), v.begin() + 3, v.end());

    std::cout << "3rd element: " << v[3] << std::endl;

    return 0;
}

6. Modifying Algorithms

copy

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> src = {1, 2, 3, 4, 5};
    std::vector<int> dest(5);

    std::copy(src.begin(), src.end(), dest.begin());

    return 0;
}

fill

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v(5);

    std::fill(v.begin(), v.end(), 42);

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 42 42 42 42 42

    return 0;
}

replace

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 2, 4, 2, 5};

    // Replace 2 with 100
    std::replace(v.begin(), v.end(), 2, 100);

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 100 3 100 4 100 5

    return 0;
}

remove / erase

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 2, 4, 2, 5};

    // remove doesn't actually delete
    auto newEnd = std::remove(v.begin(), v.end(), 2);

    // Use with erase (erase-remove idiom)
    v.erase(newEnd, v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 3 4 5

    return 0;
}

reverse

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    std::reverse(v.begin(), v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 5 4 3 2 1

    return 0;
}

unique

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 1, 2, 2, 2, 3, 3, 4};

    // Remove consecutive duplicates (requires sorted)
    auto newEnd = std::unique(v.begin(), v.end());
    v.erase(newEnd, v.end());

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 2 3 4

    return 0;
}

7. Numeric Algorithms

Include the <numeric> header.

accumulate

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // Sum
    int sum = std::accumulate(v.begin(), v.end(), 0);
    std::cout << "Sum: " << sum << std::endl;  // 15

    // Product
    int product = std::accumulate(v.begin(), v.end(), 1,
                                  std::multiplies<int>());
    std::cout << "Product: " << product << std::endl;  // 120

    // Custom
    int sumSquares = std::accumulate(v.begin(), v.end(), 0,
        [](int acc, int n) { return acc + n * n; });
    std::cout << "Sum of squares: " << sumSquares << std::endl;  // 55

    return 0;
}

iota

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> v(10);

    // Fill with consecutive values
    std::iota(v.begin(), v.end(), 1);

    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;  // 1 2 3 4 5 6 7 8 9 10

    return 0;
}

8. Set Algorithms

Works only on sorted ranges.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> a = {1, 2, 3, 4, 5};
    std::vector<int> b = {3, 4, 5, 6, 7};
    std::vector<int> result;

    // Union
    std::set_union(a.begin(), a.end(), b.begin(), b.end(),
                   std::back_inserter(result));
    // result: 1 2 3 4 5 6 7

    result.clear();

    // Intersection
    std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
                          std::back_inserter(result));
    // result: 3 4 5

    result.clear();

    // Difference
    std::set_difference(a.begin(), a.end(), b.begin(), b.end(),
                        std::back_inserter(result));
    // result: 1 2

    return 0;
}

9. min/max Algorithms

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

    // Min/max element
    auto minIt = std::min_element(v.begin(), v.end());
    auto maxIt = std::max_element(v.begin(), v.end());

    std::cout << "Min: " << *minIt << std::endl;
    std::cout << "Max: " << *maxIt << std::endl;

    // Both
    auto [minEl, maxEl] = std::minmax_element(v.begin(), v.end());
    std::cout << *minEl << " ~ " << *maxEl << std::endl;

    // Value comparison
    std::cout << std::min(3, 5) << std::endl;  // 3
    std::cout << std::max(3, 5) << std::endl;  // 5

    return 0;
}

10. all_of / any_of / none_of

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {2, 4, 6, 8, 10};

    // All satisfy?
    bool all = std::all_of(v.begin(), v.end(),
                           [](int n) { return n % 2 == 0; });
    std::cout << "All even: " << all << std::endl;  // 1

    // Any satisfy?
    bool any = std::any_of(v.begin(), v.end(),
                           [](int n) { return n > 5; });
    std::cout << "Any > 5: " << any << std::endl;  // 1

    // None satisfy?
    bool none = std::none_of(v.begin(), v.end(),
                             [](int n) { return n < 0; });
    std::cout << "No negatives: " << none << std::endl;  // 1

    return 0;
}

11. Summary

Algorithm Purpose
find, find_if Search
count, count_if Count
sort, partial_sort Sort
binary_search Binary search
transform Transform
for_each Apply function to each element
copy, fill, replace Modify
remove, unique Remove
reverse Reverse
accumulate Accumulate
min_element, max_element Min/max

Next Steps

Let's learn about templates in 12_Templates.md!

to navigate between lessons