Алгоритмы

Глава 6. Стандартная библиотека #

6.2 Алгоритмы STL #

1. Основные алгоритмы из #

Библиотека предоставляет широкий набор шаблонных функций для работы с диапазонами элементов.

Базовые алгоритмы: #

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

std::vector<int> numbers = {5, 2, 8, 1, 9, 3};

// Поиск минимума и максимума
int min_val = *std::min_element(numbers.begin(), numbers.end());
int max_val = *std::max_element(numbers.begin(), numbers.end());

// Подсчет элементов
int count_3 = std::count(numbers.begin(), numbers.end(), 3);

// Заполнение контейнера
std::fill(numbers.begin(), numbers.end(), 0);

// Перемешивание элементов
std::random_shuffle(numbers.begin(), numbers.end());

// Реверс контейнера
std::reverse(numbers.begin(), numbers.end());

Ключевые алгоритмы преобразования: #

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

// Копирование
std::copy(source.begin(), source.end(), destination.begin());

// Преобразование
std::transform(source.begin(), source.end(), destination.begin(), 
    [](int x) { return x * 2; });

2. Итераторы #

Итераторы — обобщенные указатели для навигации по контейнерам.

Типы итераторов: #

  • Input Iterator: Однонаправленный, только чтение
  • Output Iterator: Однонаправленная запись
  • Forward Iterator: Однонаправленный чтение/запись
  • Bidirectional Iterator: Двунаправленный
  • Random Access Iterator: Произвольный доступ
std::vector<int> vec = {1, 2, 3, 4, 5};

// Основные операции с итераторами
auto it = vec.begin();    // Итератор на начало
auto end_it = vec.end();  // Итератор на конец

// Перемещение итератора
++it;                     // Следующий элемент
*it;                      // Значение по итератору

3. Функциональные объекты (Функторы) #

Функциональные объекты — классы с перегруженным оператором вызова ().

// Пример функтора
class Multiplier {
public:
    int operator()(int x, int y) const {
        return x * y;
    }
};

// Использование функтора
Multiplier mult;
int result = mult(4, 5);  // result = 20

// Использование с алгоритмами
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::transform(numbers.begin(), numbers.end(), numbers.begin(), 
    [](int x) { return x * 2; });  // Лямбда как функциональный объект

Стандартные функциональные объекты: #

#include <functional>

std::vector<int> vec = {5, 2, 8, 1, 9};

// Использование стандартных функторов
std::sort(vec.begin(), vec.end(), std::greater<int>());

4. Алгоритмы сортировки #

std::vector<int> numbers = {5, 2, 8, 1, 9, 3};

// Стандартная сортировка
std::sort(numbers.begin(), numbers.end());

// Сортировка с пользовательским компаратором
std::sort(numbers.begin(), numbers.end(), 
    [](int a, int b) { return a > b; });

// Частичная сортировка
std::partial_sort(numbers.begin(), 
                  numbers.begin() + 3, 
                  numbers.end());

// Сортировка с сохранением стабильности
std::stable_sort(numbers.begin(), numbers.end());

Характеристики сортировок: #

  • std::sort: O(n log n), не стабильная
  • std::stable_sort: O(n log n), стабильная
  • std::partial_sort: Частичная сортировка первых k элементов

5. Алгоритмы поиска #

std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9};

// Бинарный поиск (требует отсортированного диапазона)
bool exists = std::binary_search(numbers.begin(), numbers.end(), 5);

// Поиск первого вхождения
auto it = std::find(numbers.begin(), numbers.end(), 5);
if (it != numbers.end()) {
    // Элемент найден
    size_t index = std::distance(numbers.begin(), it);
}

// Поиск элемента, удовлетворяющего условию
auto pred_it = std::find_if(numbers.begin(), numbers.end(), 
    [](int x) { return x > 6; });

// Подсчет элементов, удовлетворяющих условию
int count = std::count_if(numbers.begin(), numbers.end(), 
    [](int x) { return x % 2 == 0; });

Рекомендации по использованию алгоритмов STL #

  1. Предпочтение алгоритмам STL над ручной реализацией
  2. Использование лямбда-выражений для кастомизации
  3. Внимание к сложности алгоритмов
  4. Проверка совместимости итераторов
  5. Осторожность с изменением контейнеров во время итерации

Заключение #

Алгоритмы STL предоставляют мощный и эффективный инструментарий для работы с данными. Понимание их возможностей позволяет писать более чистый, производительный и выразительный код.