Алгоритмы STL в C++: find, count, sort, transform и другие полезные функции

Алгоритмы STL в C++: find, count, sort, transform и другие полезные функции

Алгоритмы STL в C++: find, count, sort, transform и другие полезные функции

Поисковый запрос, которому соответствует эта статья: алгоритмы STL C++ примеры. Если вы уже умеете работать с массивами или контейнерами, следующий важный шаг — научиться использовать готовые алгоритмы из стандартной библиотеки. Они находятся в заголовке <algorithm> и позволяют заменить многие ручные циклы понятными функциями.

Главная идея STL-алгоритмов проста: алгоритм работает не с конкретным контейнером, а с диапазоном, заданным двумя итераторами: началом и концом. Например, v.begin() и v.end().

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

int main() {
    std::vector<int> numbers = {5, 2, 8, 2, 1};

    std::sort(numbers.begin(), numbers.end());

    for (int x : numbers) {
        std::cout << x << ' ';
    }
}

Результат:

1 2 2 5 8

Почему лучше использовать алгоритмы STL, а не писать всё вручную

  • Меньше ошибок. Готовые алгоритмы уже протестированы и оптимизированы.
  • Код короче. Вместо десяти строк цикла часто достаточно одной функции.
  • Лучше читаемость. std::find сразу говорит: здесь выполняется поиск.
  • Единый стиль. Один подход работает с vector, array, deque, строками и другими контейнерами.
  • Если вы хотите системно разобраться не только в STL, но и в синтаксисе, ООП, памяти и реальных проектах, посмотрите курс «Программирование на C++ с Нуля до Гуру» — пошаговый путь к уверенному C++. Он хорошо дополняет практику с такими темами, как алгоритмы стандартной библиотеки.

    std::find: поиск элемента

    std::find ищет первое вхождение значения в диапазоне. Если элемент найден, возвращается итератор на него. Если нет — возвращается итератор конца, например v.end().

    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> numbers = {10, 20, 30, 40};
    
        auto it = std::find(numbers.begin(), numbers.end(), 30);
    
        if (it != numbers.end()) {
            std::cout << "Найдено: " << *it << 'n';
        } else {
            std::cout << "Не найденоn";
        }
    }
    

    Важный совет: никогда не разыменовывайте итератор, пока не проверили, что он не равен end(). Иначе программа может работать некорректно.

    std::count и std::count_if: подсчёт элементов

    std::count считает элементы, равные заданному значению. А std::count_if считает элементы по условию.

    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> numbers = {1, 2, 2, 3, 4, 6, 8};
    
        int twos = std::count(numbers.begin(), numbers.end(), 2);
    
        int even = std::count_if(numbers.begin(), numbers.end(), [](int x) {
            return x % 2 == 0;
        });
    
        std::cout << "Двоек: " << twos << 'n';
        std::cout << "Чётных: " << even << 'n';
    }
    

    Лямбда-функция [](int x) { return x % 2 == 0; } — это короткая функция прямо на месте вызова. Она возвращает true, если число подходит под условие.

    std::sort: сортировка по возрастанию и по своему правилу

    std::sort сортирует диапазон. По умолчанию — по возрастанию.

    std::vector<int> numbers = {5, 1, 9, 3};
    std::sort(numbers.begin(), numbers.end());

    Для сортировки по убыванию можно передать компаратор:

    std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
        return a > b;
    });

    Практический пример: отсортируем пользователей по возрасту.

    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <vector>
    
    struct User {
        std::string name;
        int age;
    };
    
    int main() {
        std::vector<User> users = {
            {"Анна", 25},
            {"Игорь", 19},
            {"Мария", 31}
        };
    
        std::sort(users.begin(), users.end(), [](const User& a, const User& b) {
            return a.age < b.age;
        });
    
        for (const User& user : users) {
            std::cout << user.name << ": " << user.age << 'n';
        }
    }
    

    Рекомендация: если объект тяжёлый, передавайте его в компаратор по константной ссылке: const User&, а не просто User. Так вы избежите лишних копирований.

    std::any_of, std::all_of, std::none_of: проверка условий

    Эти алгоритмы делают код выразительнее:

  • any_of — хотя бы один элемент подходит;
  • all_of — все элементы подходят;
  • none_of — ни один элемент не подходит.
  • std::vector<int> scores = {80, 95, 70, 100};
    
    bool hasPerfect = std::any_of(scores.begin(), scores.end(), [](int x) {
        return x == 100;
    });
    
    bool allPassed = std::all_of(scores.begin(), scores.end(), [](int x) {
        return x >= 60;
    });

    Такой код почти читается как обычный текст: есть ли идеальная оценка, все ли сдали экзамен.

    std::transform: преобразование коллекции

    std::transform применяет функцию к каждому элементу и записывает результат в другой диапазон. Например, получим квадраты чисел.

    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> numbers = {1, 2, 3, 4};
        std::vector<int> squares(numbers.size());
    
        std::transform(numbers.begin(), numbers.end(), squares.begin(), [](int x) {
            return x * x;
        });
    
        for (int x : squares) {
            std::cout << x << ' ';
        }
    }
    

    Типичная ошибка новичков — забыть заранее выделить место в контейнере результата. В примере выше это сделано строкой std::vector<int> squares(numbers.size());.

    std::remove и erase: правильное удаление элементов

    Название std::remove может запутать: сам по себе он не уменьшает размер контейнера. Он переставляет элементы и возвращает итератор на новый логический конец. Поэтому для вектора обычно используют идиому erase-remove.

    std::vector<int> numbers = {1, 2, 3, 2, 4};
    
    numbers.erase(
        std::remove(numbers.begin(), numbers.end(), 2),
        numbers.end()
    );
    

    После этого в векторе останутся значения 1, 3, 4. Для удаления по условию используйте std::remove_if.

    numbers.erase(
        std::remove_if(numbers.begin(), numbers.end(), [](int x) {
            return x % 2 == 0;
        }),
        numbers.end()
    );

    Практические рекомендации

  • Подключайте #include <algorithm>, если используете алгоритмы STL.
  • Всегда проверяйте результат find перед разыменованием итератора.
  • Для условий используйте count_if, find_if, remove_if, а не сложные ручные циклы.
  • В компараторах сортировки возвращайте строгое условие: например, a.age < b.age, а не a.age <= b.age.
  • Не бойтесь лямбда-функций: с алгоритмами STL они встречаются постоянно.
  • Итог

    Алгоритмы STL в C++ — это базовый инструмент, который стоит освоить как можно раньше. std::find помогает искать, std::count_if — считать по условию, std::sort — сортировать, std::transform — преобразовывать данные, а erase-remove — корректно удалять элементы. Чем чаще вы используете стандартные алгоритмы, тем чище и надёжнее становится ваш C++-код.

    Источник

    НЕТ КОММЕНТАРИЕВ

    Оставить комментарий