cpp

Algorithms

03_Algorithms⚙️
/**
 * ============================================================
 * C++ STL ALGORITHMS
 * ============================================================
 * 
 * This file covers:
 * - Non-modifying algorithms (find, count, search)
 * - Modifying algorithms (copy, transform, replace)
 * - Sorting algorithms (sort, stable_sort, partial_sort)
 * - Numeric algorithms (accumulate, inner_product)
 * - Set algorithms (union, intersection, difference)
 * - Using lambdas with algorithms
 * 
 * Compile: g++ -std=c++17 -Wall 01_algorithms.cpp -o algorithms
 * Run: ./algorithms
 * 
 * ============================================================
 */

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <numeric>
#include <functional>
#include <random>
#include <iterator>

using namespace std;

// Helper to print containers
template <typename Container>
void print(const string& label, const Container& c) {
    cout << label << ": ";
    for (const auto& elem : c) cout << elem << " ";
    cout << endl;
}

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

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

    // ========================================================
    // PART 1: NON-MODIFYING ALGORITHMS
    // ========================================================
    
    cout << "--- PART 1: NON-MODIFYING ALGORITHMS ---" << endl << endl;
    
    vector<int> data = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    print("data", data);
    
    // find
    auto it = find(data.begin(), data.end(), 5);
    if (it != data.end()) {
        cout << "find(5): found at index " << distance(data.begin(), it) << endl;
    }
    
    // find_if
    auto evenIt = find_if(data.begin(), data.end(), [](int x) { return x % 2 == 0; });
    cout << "find_if(even): " << *evenIt << endl;
    
    // find_if_not
    auto notSmall = find_if_not(data.begin(), data.end(), [](int x) { return x < 5; });
    cout << "find_if_not(< 5): " << *notSmall << endl;
    
    // count / count_if
    cout << "count(5): " << count(data.begin(), data.end(), 5) << endl;
    cout << "count_if(> 3): " << count_if(data.begin(), data.end(), 
                                          [](int x) { return x > 3; }) << endl;
    
    // all_of / any_of / none_of
    cout << "all_of(> 0): " << all_of(data.begin(), data.end(), 
                                      [](int x) { return x > 0; }) << endl;
    cout << "any_of(> 8): " << any_of(data.begin(), data.end(),
                                      [](int x) { return x > 8; }) << endl;
    cout << "none_of(< 0): " << none_of(data.begin(), data.end(),
                                        [](int x) { return x < 0; }) << endl;
    
    // search - find subsequence
    vector<int> pattern = {1, 5};
    auto searchIt = search(data.begin(), data.end(), pattern.begin(), pattern.end());
    if (searchIt != data.end()) {
        cout << "search({1,5}): found at index " << distance(data.begin(), searchIt) << endl;
    }
    
    // adjacent_find
    vector<int> adj = {1, 2, 3, 3, 4, 5};
    auto adjIt = adjacent_find(adj.begin(), adj.end());
    if (adjIt != adj.end()) {
        cout << "adjacent_find: " << *adjIt << " at index " 
             << distance(adj.begin(), adjIt) << endl;
    }
    
    // mismatch
    vector<int> v1 = {1, 2, 3, 4, 5};
    vector<int> v2 = {1, 2, 4, 4, 5};
    auto [mis1, mis2] = mismatch(v1.begin(), v1.end(), v2.begin());
    cout << "mismatch: v1=" << *mis1 << ", v2=" << *mis2 << endl;
    
    cout << endl;

    // ========================================================
    // PART 2: MODIFYING ALGORITHMS
    // ========================================================
    
    cout << "--- PART 2: MODIFYING ALGORITHMS ---" << endl << endl;
    
    // copy
    vector<int> src = {1, 2, 3, 4, 5};
    vector<int> dest(5);
    copy(src.begin(), src.end(), dest.begin());
    print("copy", dest);
    
    // copy_if
    vector<int> evens;
    copy_if(src.begin(), src.end(), back_inserter(evens),
            [](int x) { return x % 2 == 0; });
    print("copy_if(even)", evens);
    
    // copy_n
    vector<int> first3(3);
    copy_n(src.begin(), 3, first3.begin());
    print("copy_n(3)", first3);
    
    // transform
    vector<int> doubled(src.size());
    transform(src.begin(), src.end(), doubled.begin(),
              [](int x) { return x * 2; });
    print("transform(*2)", doubled);
    
    // transform with two inputs
    vector<int> added(src.size());
    transform(src.begin(), src.end(), doubled.begin(), added.begin(),
              [](int a, int b) { return a + b; });
    print("transform(src+doubled)", added);
    
    // fill
    vector<int> filled(5);
    fill(filled.begin(), filled.end(), 42);
    print("fill(42)", filled);
    
    // generate
    vector<int> generated(5);
    int n = 0;
    generate(generated.begin(), generated.end(), [&n]() { return n++; });
    print("generate(counter)", generated);
    
    // replace / replace_if
    vector<int> rep = {1, 2, 3, 2, 4, 2, 5};
    replace(rep.begin(), rep.end(), 2, 99);
    print("replace(2->99)", rep);
    
    vector<int> rep2 = {1, 2, 3, 4, 5, 6};
    replace_if(rep2.begin(), rep2.end(), [](int x) { return x > 3; }, 0);
    print("replace_if(>3->0)", rep2);
    
    // remove (doesn't actually remove - moves to end)
    vector<int> rem = {1, 2, 3, 2, 4, 2, 5};
    auto newEnd = remove(rem.begin(), rem.end(), 2);
    print("remove(2) before erase", rem);
    rem.erase(newEnd, rem.end());  // Actually remove
    print("after erase", rem);
    
    // unique
    vector<int> dup = {1, 1, 2, 2, 2, 3, 3, 4};
    auto uniqueEnd = unique(dup.begin(), dup.end());
    dup.erase(uniqueEnd, dup.end());
    print("unique", dup);
    
    // reverse
    vector<int> toRev = {1, 2, 3, 4, 5};
    reverse(toRev.begin(), toRev.end());
    print("reverse", toRev);
    
    // rotate
    vector<int> toRot = {1, 2, 3, 4, 5};
    rotate(toRot.begin(), toRot.begin() + 2, toRot.end());
    print("rotate(+2)", toRot);
    
    cout << endl;

    // ========================================================
    // PART 3: SORTING ALGORITHMS
    // ========================================================
    
    cout << "--- PART 3: SORTING ALGORITHMS ---" << endl << endl;
    
    // sort
    vector<int> toSort = {5, 2, 8, 1, 9, 3, 7};
    sort(toSort.begin(), toSort.end());
    print("sort", toSort);
    
    // sort descending
    sort(toSort.begin(), toSort.end(), greater<int>());
    print("sort(desc)", toSort);
    
    // sort with custom comparator
    vector<string> words = {"banana", "apple", "cherry", "date"};
    sort(words.begin(), words.end(), [](const string& a, const string& b) {
        return a.length() < b.length();  // By length
    });
    print("sort(by length)", words);
    
    // stable_sort (preserves order of equal elements)
    vector<pair<int, string>> items = {{2, "b"}, {1, "a"}, {2, "c"}, {1, "d"}};
    stable_sort(items.begin(), items.end(), 
                [](const auto& a, const auto& b) { return a.first < b.first; });
    cout << "stable_sort: ";
    for (const auto& [num, str] : items) cout << "(" << num << "," << str << ") ";
    cout << endl;
    
    // partial_sort
    vector<int> partial = {5, 2, 8, 1, 9, 3, 7};
    partial_sort(partial.begin(), partial.begin() + 3, partial.end());
    print("partial_sort(3)", partial);  // First 3 are smallest, rest unsorted
    
    // nth_element
    vector<int> nth = {5, 2, 8, 1, 9, 3, 7};
    nth_element(nth.begin(), nth.begin() + 3, nth.end());
    print("nth_element(3)", nth);
    cout << "4th smallest: " << nth[3] << endl;
    
    // is_sorted
    vector<int> sorted = {1, 2, 3, 4, 5};
    cout << "is_sorted({1,2,3,4,5}): " << is_sorted(sorted.begin(), sorted.end()) << endl;
    
    cout << endl;

    // ========================================================
    // PART 4: BINARY SEARCH ALGORITHMS
    // ========================================================
    
    cout << "--- PART 4: BINARY SEARCH ---" << endl << endl;
    
    vector<int> sorted2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    print("sorted", sorted2);
    
    // binary_search
    cout << "binary_search(5): " << binary_search(sorted2.begin(), sorted2.end(), 5) << endl;
    cout << "binary_search(10): " << binary_search(sorted2.begin(), sorted2.end(), 10) << endl;
    
    // lower_bound (first element >= value)
    auto lb = lower_bound(sorted2.begin(), sorted2.end(), 5);
    cout << "lower_bound(5): index " << distance(sorted2.begin(), lb) << endl;
    
    // upper_bound (first element > value)
    auto ub = upper_bound(sorted2.begin(), sorted2.end(), 5);
    cout << "upper_bound(5): index " << distance(sorted2.begin(), ub) << endl;
    
    // equal_range (both bounds)
    vector<int> withDups = {1, 2, 2, 2, 3, 4, 5};
    auto [lo, hi] = equal_range(withDups.begin(), withDups.end(), 2);
    cout << "equal_range(2): [" << distance(withDups.begin(), lo) 
         << ", " << distance(withDups.begin(), hi) << ")" << endl;
    
    cout << endl;

    // ========================================================
    // PART 5: NUMERIC ALGORITHMS
    // ========================================================
    
    cout << "--- PART 5: NUMERIC ALGORITHMS ---" << endl << endl;
    
    vector<int> nums = {1, 2, 3, 4, 5};
    print("nums", nums);
    
    // accumulate
    int sum = accumulate(nums.begin(), nums.end(), 0);
    cout << "sum: " << sum << endl;
    
    // accumulate with custom operation
    int product = accumulate(nums.begin(), nums.end(), 1, multiplies<int>());
    cout << "product: " << product << endl;
    
    // inner_product (dot product)
    vector<int> a = {1, 2, 3};
    vector<int> b = {4, 5, 6};
    int dot = inner_product(a.begin(), a.end(), b.begin(), 0);
    cout << "dot product: " << dot << " (1*4 + 2*5 + 3*6 = 32)" << endl;
    
    // partial_sum
    vector<int> partial_sums(nums.size());
    partial_sum(nums.begin(), nums.end(), partial_sums.begin());
    print("partial_sum", partial_sums);
    
    // adjacent_difference
    vector<int> diffs(nums.size());
    adjacent_difference(nums.begin(), nums.end(), diffs.begin());
    print("adjacent_diff", diffs);
    
    // iota
    vector<int> seq(10);
    iota(seq.begin(), seq.end(), 1);  // 1, 2, 3, ...
    print("iota(1)", seq);
    
    cout << endl;

    // ========================================================
    // PART 6: SET ALGORITHMS
    // ========================================================
    
    cout << "--- PART 6: SET ALGORITHMS ---" << endl << endl;
    
    vector<int> s1 = {1, 2, 3, 4, 5};
    vector<int> s2 = {3, 4, 5, 6, 7};
    print("s1", s1);
    print("s2", s2);
    
    // set_union
    vector<int> unionResult;
    set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), back_inserter(unionResult));
    print("union", unionResult);
    
    // set_intersection
    vector<int> intersectResult;
    set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), 
                     back_inserter(intersectResult));
    print("intersection", intersectResult);
    
    // set_difference
    vector<int> diffResult;
    set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), 
                   back_inserter(diffResult));
    print("difference(s1-s2)", diffResult);
    
    // set_symmetric_difference
    vector<int> symDiff;
    set_symmetric_difference(s1.begin(), s1.end(), s2.begin(), s2.end(),
                             back_inserter(symDiff));
    print("symmetric_diff", symDiff);
    
    // includes
    vector<int> subset = {3, 4};
    cout << "s1 includes {3,4}: " << includes(s1.begin(), s1.end(),
                                              subset.begin(), subset.end()) << endl;
    
    cout << endl;

    // ========================================================
    // PART 7: MIN/MAX AND PERMUTATIONS
    // ========================================================
    
    cout << "--- PART 7: MIN/MAX & PERMUTATIONS ---" << endl << endl;
    
    vector<int> vals = {3, 1, 4, 1, 5, 9, 2, 6};
    
    // min_element / max_element
    auto minIt = min_element(vals.begin(), vals.end());
    auto maxIt = max_element(vals.begin(), vals.end());
    cout << "min: " << *minIt << " at index " << distance(vals.begin(), minIt) << endl;
    cout << "max: " << *maxIt << " at index " << distance(vals.begin(), maxIt) << endl;
    
    // minmax_element
    auto [minElem, maxElem] = minmax_element(vals.begin(), vals.end());
    cout << "minmax: " << *minElem << ", " << *maxElem << endl;
    
    // clamp (C++17)
    cout << "clamp(7, 1, 5): " << clamp(7, 1, 5) << endl;
    cout << "clamp(3, 1, 5): " << clamp(3, 1, 5) << endl;
    cout << "clamp(-2, 1, 5): " << clamp(-2, 1, 5) << endl;
    
    // next_permutation
    vector<int> perm = {1, 2, 3};
    cout << "\nPermutations of {1,2,3}:" << endl;
    do {
        for (int x : perm) cout << x << " ";
        cout << endl;
    } while (next_permutation(perm.begin(), perm.end()));
    
    // shuffle
    vector<int> toShuffle = {1, 2, 3, 4, 5};
    random_device rd;
    mt19937 gen(rd());
    shuffle(toShuffle.begin(), toShuffle.end(), gen);
    print("\nshuffled", toShuffle);
    
    cout << endl;

    // ========================================================
    // ALGORITHM SUMMARY
    // ========================================================
    
    cout << "--- ALGORITHM CATEGORIES ---" << endl << endl;
    
    cout << "Non-modifying:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "find, find_if, count, count_if" << endl;
    cout << "all_of, any_of, none_of" << endl;
    cout << "search, mismatch, equal" << endl;
    
    cout << "\nModifying:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "copy, copy_if, transform" << endl;
    cout << "fill, generate, replace" << endl;
    cout << "remove, unique, reverse, rotate" << endl;
    
    cout << "\nSorting:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "sort, stable_sort, partial_sort" << endl;
    cout << "nth_element, is_sorted" << endl;
    
    cout << "\nBinary Search:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "binary_search, lower_bound, upper_bound" << endl;
    cout << "equal_range" << endl;
    
    cout << "\nNumeric:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "accumulate, inner_product" << endl;
    cout << "partial_sum, adjacent_difference, iota" << endl;
    
    cout << endl;

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

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Word processor:
 *    - Read text, count word frequency
 *    - Find longest word, most common word
 *    - Remove duplicates, sort by frequency
 * 
 * 2. Statistics calculator:
 *    - Calculate mean, median, mode, std deviation
 *    - Use accumulate, sort, nth_element
 *    - Handle edge cases (empty input)
 * 
 * 3. Set operations puzzle:
 *    - Given multiple sets, find elements in:
 *      - All sets (multi-set intersection)
 *      - Exactly one set (symmetric diff)
 *      - At least N sets
 * 
 * 4. Custom sort:
 *    - Sort students by GPA, then by name
 *    - Use stable_sort with multiple criteria
 *    - Partition into pass/fail groups
 */
Algorithms - C++ Tutorial | DeepML