0Pricing
C++ Academy · Урок

Пользовательские компараторы

Управляйте порядком сортировки

«Пользовательские компараторы» — бесплатный урок C++ Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Зачем нужны пользовательские компараторы

По умолчанию упорядоченные контейнеры сортируют элементы с помощью std::less (по возрастанию). Пользовательский компаратор позволяет изменить этот порядок, например сортировать по убыванию или по определённому полю.

#include <iostream>
#include <set>

int main() {
    std::set<int> ascending{3, 1, 2};
    for (int x : ascending) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Сортировка по убыванию с помощью std::greater

Самый простой пользовательский компаратор — стандартный функтор std::greater, который сортирует элементы по убыванию.

#include <iostream>
#include <set>
#include <functional>

int main() {
    std::set<int, std::greater<int>> s{3, 1, 2};
    for (int x : s) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Компаратор для отображения

Компаратор — это третий параметр шаблона std::map. В данном случае ключи сортируются от большего к меньшему.

#include <iostream>
#include <map>
#include <functional>

int main() {
    std::map<int, std::string, std::greater<int>> m{
        {1, "one"}, {3, "three"}, {2, "two"}
    };
    for (const auto& [k, v] : m) std::cout << k << ':' << v << ' ';
    std::cout << '\n';
    return 0;
}

Как работают компараторы

Компаратор — это вызываемый объект, принимающий два аргумента и возвращающий true, если первый элемент должен находиться перед вторым. Он должен задавать строгое слабое упорядочивание.

#include <iostream>

struct Less {
    bool operator()(int a, int b) const { return a < b; }
};

int main() {
    Less cmp;
    std::cout << std::boolalpha << cmp(2, 5) << '\n';
    std::cout << cmp(5, 2) << '\n';
    return 0;
}

Компаратор на основе пользовательской структуры

Определите собственный функтор-структуру с помощью operator() и передайте её тип как компаратор.

#include <iostream>
#include <set>

struct ByAbs {
    bool operator()(int a, int b) const {
        return (a < 0 ? -a : a) < (b < 0 ? -b : b);
    }
};

int main() {
    std::set<int, ByAbs> s{-5, 3, -1, 4};
    for (int x : s) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Сортировка строк по длине

Компараторы могут сравнивать любые свойства. Здесь строки упорядочиваются по длине, а при одинаковой длине — в алфавитном порядке.

#include <iostream>
#include <set>
#include <string>

struct ByLen {
    bool operator()(const std::string& a, const std::string& b) const {
        if (a.size() != b.size()) return a.size() < b.size();
        return a < b;
    }
};

int main() {
    std::set<std::string, ByLen> s{"bbb", "a", "cc", "dd"};
    for (const auto& x : s) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Зачем нужны дополнительные критерии сравнения

Если компаратор считает, что ни один из элементов не должен находиться перед другим, контейнер считает их равными. В set это означает, что один элемент будет отброшен как дубликат.

#include <iostream>
#include <set>
#include <string>

struct LenOnly {
    bool operator()(const std::string& a, const std::string& b) const {
        return a.size() < b.size();
    }
};

int main() {
    std::set<std::string, LenOnly> s{"ab", "cd", "x"};
    std::cout << s.size() << " elements\n";
    return 0;
}

Лямбда-выражения как компараторы

Можно использовать лямбда-выражение, передав его тип через decltype, а само лямбда-выражение — конструктору.

#include <iostream>
#include <set>

int main() {
    auto cmp = [](int a, int b) { return a > b; };
    std::set<int, decltype(cmp)> s(cmp);
    s.insert(1);
    s.insert(3);
    s.insert(2);
    for (int x : s) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Компараторы в priority_queue

Компараторы также настраивают std::priority_queue. С std::greater он превращается в кучу с минимальным элементом наверху.

#include <iostream>
#include <queue>
#include <vector>
#include <functional>

int main() {
    std::priority_queue<int, std::vector<int>, std::greater<int>> pq;
    pq.push(5); pq.push(1); pq.push(3);
    while (!pq.empty()) { std::cout << pq.top() << ' '; pq.pop(); }
    std::cout << '\n';
    return 0;
}

Сравнение пар

Чтобы сортировать набор пар по второму элементу, напишите компаратор, который проверяет .second.

#include <iostream>
#include <set>
#include <utility>

struct BySecond {
    bool operator()(const std::pair<int,int>& a, const std::pair<int,int>& b) const {
        return a.second < b.second;
    }
};

int main() {
    std::set<std::pair<int,int>, BySecond> s{{1, 9}, {2, 3}, {3, 6}};
    for (const auto& p : s) std::cout << p.first << ':' << p.second << ' ';
    std::cout << '\n';
    return 0;
}

Прозрачные компараторы

Использование std::less<> (с пустыми угловыми скобками) включает гетерогенный поиск в C++14 и позволяет избежать временных преобразований ключей.

#include <iostream>
#include <set>
#include <functional>

int main() {
    std::set<int, std::less<>> s{1, 2, 3};
    std::cout << (s.find(2) != s.end() ? "found" : "no") << '\n';
    return 0;
}

Быстрая проверка

Проверьте, насколько хорошо Вы поняли, как компараторы определяют равенство.

Повторение

Вы узнали, что пользовательские компараторы:

  • изменяют порядок через параметр шаблона компаратора контейнера
  • могут быть представлены как std::greater, функтор-структура или лямбда-выражение (через decltype)
  • определяют равенство через эквивалентность, поэтому всегда включайте дополнительный критерий сравнения, чтобы не потерять различные элементы

Следующий курс посвящён быстрому поиску на основе хеширования с помощью std::unordered_map.

Часто задаваемые вопросы

Урок «Пользовательские компараторы» бесплатный?

Да — полный текст урока «Пользовательские компараторы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «Пользовательские компараторы»?

Управляйте порядком сортировки Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Пользовательские компараторы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. std::map
  2. std::set
  3. multimap и multiset
  4. Пользовательские компараторы
← Назад к C++ Academy