<MyRusakov.ru />

Разработчик игр на Unreal Engine

Разработчик игр на Unreal Engine

Этот комплект с нуля всего за 7 месяцев сделает Вас Unreal-разработчиком. И при этом учиться достаточно 1 час в день.

Начнёте Вы с основ программирования, постепенно перейдя к C++. Затем очень подробно изучите Unreal Engine, и после научитесь программировать на C++ в Unreal Engine. В конце создадите крупный проект на C++ в Unreal Engine для своего портфолио.

Комплект содержит:

- 416 видеоуроков

- 95 часов видео

- 1024 задания для закрепления материала из уроков

- 3 финальных тестирования

- 4 сертификата

- 12 Бонусных курсов

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

std::unordered_map в C++: хеш-таблица для быстрого поиска с примерами

std::unordered_map в C++: хеш-таблица для быстрого поиска с примерами

std::unordered_map в C++ — это контейнер из стандартной библиотеки, который хранит данные в формате «ключ-значение» и обеспечивает очень быстрый доступ по ключу. Если говорить проще, это хеш-таблица: вы передаёте ключ, а контейнер почти мгновенно находит связанное с ним значение.

Поисковый запрос, под который полезна эта статья: «unordered_map C++ примеры». Разберём синтаксис, основные операции, практические задачи и ошибки, которые часто допускают начинающие.

Когда нужен std::unordered_map

Используйте std::unordered_map, когда вам нужно быстро:

  • найти значение по уникальному ключу;
  • посчитать количество одинаковых элементов;
  • хранить настройки, кэш, словарь, таблицу пользователей;
  • проверять, встречался ли объект раньше.

Главная особенность: элементы внутри unordered_map не отсортированы. Если вам нужен обход ключей в порядке возрастания, лучше использовать std::map. Если порядок не важен, чаще всего unordered_map быстрее.

Подключение и базовый пример

Для работы нужен заголовочный файл <unordered_map>. Рассмотрим простой словарь возрастов:

#include <iostream>
#include <unordered_map>
#include <string>

int main() {
    std::unordered_map<std::string, int> ages;

    ages["Anna"] = 25;
    ages["Ivan"] = 30;
    ages["Oleg"] = 22;

    std::cout << "Возраст Ivan: " << ages["Ivan"] << '\n';

    return 0;
}

Тип std::unordered_map<std::string, int> означает: ключ — строка, значение — целое число.

Добавление элементов: operator[] и insert

Самый простой способ добавить или изменить элемент — квадратные скобки:

std::unordered_map<std::string, int> scores;

scores["Alice"] = 100;  // добавление
scores["Alice"] = 150;  // изменение значения

Но у operator[] есть важная особенность: если ключа нет, он будет создан автоматически со значением по умолчанию. Для int это будет 0, для std::string — пустая строка.

Если вы не хотите случайно создавать элемент, используйте insert или emplace:

std::unordered_map<std::string, int> scores;

scores.insert({"Bob", 80});
scores.emplace("Kate", 95);

emplace часто предпочтительнее, потому что создаёт объект прямо внутри контейнера без лишнего копирования.

Проверка наличия ключа

Типичная ошибка новичков — проверять наличие ключа через operator[]:

if (scores["Tom"] == 0) {
    // Плохо: если ключа Tom не было, он только что появился в map
}

Правильный способ — использовать find:

auto it = scores.find("Tom");

if (it != scores.end()) {
    std::cout << "Tom найден, баллы: " << it->second << '\n';
} else {
    std::cout << "Tom не найден\n";
}

Начиная с C++20 можно использовать более читаемый метод contains:

if (scores.contains("Tom")) {
    std::cout << "Ключ существует\n";
}

Практический пример: подсчёт частоты слов

Одна из самых популярных задач для std::unordered_map — посчитать, сколько раз встречается каждый элемент. Например, частоту слов:

#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> words = {
        "cpp", "java", "cpp", "python", "cpp", "java"
    };

    std::unordered_map<std::string, int> frequency;

    for (const auto& word : words) {
        ++frequency[word];
    }

    for (const auto& pair : frequency) {
        std::cout << pair.first << ": " << pair.second << '\n';
    }

    return 0;
}

Здесь выражение ++frequency[word] работает удобно: если слова ещё нет, оно создаётся со значением 0, затем увеличивается до 1.

Обход элементов

Обходить unordered_map можно через range-based for. Но помните: порядок вывода не гарантирован.

for (const auto& [name, age] : ages) {
    std::cout << name << " - " << age << '\n';
}

Синтаксис [name, age] называется structured bindings и доступен с C++17. Если вы изучаете современный C++ и хотите уверенно разбираться не только в контейнерах, но и в базовых принципах языка, посмотрите курс «C++ с нуля до уверенного уровня: практика, задачи и понятные объяснения».

Удаление элементов

Удалить элемент можно по ключу:

ages.erase("Oleg");

Метод erase возвращает количество удалённых элементов. Для unordered_map это будет либо 0, либо 1, потому что ключи уникальны.

if (ages.erase("Oleg") == 1) {
    std::cout << "Элемент удалён\n";
} else {
    std::cout << "Такого ключа не было\n";
}

at() против operator[]

Для чтения значений можно использовать at(). В отличие от квадратных скобок, он не создаёт новый элемент. Если ключа нет, будет выброшено исключение std::out_of_range.

try {
    std::cout << ages.at("Maria") << '\n';
} catch (const std::out_of_range&) {
    std::cout << "Ключ Maria не найден\n";
}

Практическое правило: для добавления и счётчиков удобен operator[], для безопасного чтения — find, contains или at.

Производительность и reserve

В среднем операции поиска, вставки и удаления в std::unordered_map выполняются за O(1). Но при большом количестве вставок контейнер может перераспределять внутренние корзины. Если вы заранее знаете примерное число элементов, используйте reserve:

std::unordered_map<std::string, int> users;
users.reserve(10000);

Это может заметно ускорить программу, если вы загружаете много данных, например из файла или базы.

Ключи пользовательского типа

Для стандартных типов вроде int, std::string, long long хеш уже определён. Но если ключ — ваша структура, нужно указать, как сравнивать объекты и как вычислять хеш.

#include <iostream>
#include <unordered_map>

struct Point {
    int x;
    int y;

    bool operator==(const Point& other) const {
        return x == other.x && y == other.y;
    }
};

struct PointHash {
    std::size_t operator()(const Point& p) const {
        return std::hash<int>{}(p.x) ^ (std::hash<int>{}(p.y) << 1);
    }
};

int main() {
    std::unordered_map<Point, std::string, PointHash> points;

    points[{10, 20}] = "Дом";
    points[{5, 7}] = "Магазин";

    std::cout << points[{10, 20}] << '\n';
}

Для новичков это уже более продвинутая тема, но важно знать: unordered_map может работать не только со строками и числами.

Частые ошибки

  • Ожидать отсортированный порядок. В unordered_map порядок обхода непредсказуем.
  • Использовать operator[] только для проверки. Так можно случайно добавить новый элемент.
  • Забывать про reserve. При массовой вставке предварительное резервирование ускоряет работу.
  • Выбирать unordered_map всегда. Если нужны отсортированные ключи или диапазонные запросы, берите std::map.

Краткая шпаргалка

std::unordered_map<std::string, int> m;

m["one"] = 1;              // добавить или изменить
m.emplace("two", 2);       // добавить эффективнее

if (m.find("one") != m.end()) {
    // ключ найден
}

m.erase("two");            // удалить по ключу
std::cout << m.size();     // количество элементов

Вывод

std::unordered_map в C++ — отличный контейнер для быстрого доступа по ключу. Он особенно полезен для словарей, подсчёта частот, кэшей и проверки уникальности. Главное — помнить, что элементы не сортируются, а operator[] может создавать новые записи. Если эти особенности учитывать, хеш-таблица станет одним из самых удобных инструментов в вашем C++-коде.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.