Баннер мобильный (3) Пройти тест

Ассоциативные контейнеры в C++: что это такое и как работает

Map, set и другие контейнеры

Разбор

21 октября 2025

Поделиться

Скопировано
Ассоциативные контейнеры в C++: что это такое и как работает

Содержание

    Узнаем, какие бывают контейнеры в языке программирования C++ и что это вообще такое. Более подробно рассмотрим, что из себя представляют ассоциативные контейнеры map и set.

    Что такое контейнеры в C++, для чего они нужны и какие бывают

    В языке программирования C++ часто нужно работать с коллекциями объектов. Контейнеры как раз и представляют собой эти коллекции. Они хранят элементы определенного типа и позволяют совершать над ними различные операции. 

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

    В C++ контейнеры бывают двух видов: последовательные и ассоциативные. Последовательные контейнеры похожи на обычные массивы и бывают разных типов. Например:

    • array — коллекция фиксированного размера. Не позволяет добавлять или удалять элементы;
    • vector — имеет переменный размер. Можно добавлять и удалять элементы.

    Ассоциативные контейнеры — это контейнеры, где с каждым элементом связан ключ доступа. В языке C++ ассоциативные контейнеры представлены картами (словарями) map и множествами set. 

    Контейнер map в C++

    Контейнеры map хранят пары «ключ — значение». К каждому значению можно получить доступ по уникальному ключу. Такие контейнеры по-другому называются картами или словарями.

    Как создать контейнер map

    Создадим контейнер, который будет содержать названия стран в качестве ключей и их столиц в качестве значений. 

    Сначала подключаем заголовочные файлы <map> и <iostream>. Первый нужен для работы со словарем, а второй — для управления чтением и записью в стандартные потоки. В частности, он понадобится для вывода результатов в консоль. В самом начале исходника пишем:

    #include <iostream>
    #include <map>

    Заголовки подключены. Теперь объявляем пустой контейнер map. Делаем это в функции main, которая является точкой входа в приложение:

    int main() {
            std::map<std::string, std::string> capitals;
      }

    Мы создали контейнер map с именем capitals. Ключи и значения в нем будут иметь тип string, то есть являться строками. Теперь заполним этот контейнер:

    capitals["Россия"] = "Москва";
    capitals["Северная Корея"] = "Пхеньян";
    capitals["Китай"] = "Пекин";

    Как видим, чтобы установить необходимое значение, нужно использовать вот такой простой синтаксис:

    map[ключ]=значение

    Получение значений

    Чтобы получить значение, нужно просто прописать в нужном месте:

    map[ключ]

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

    std::cout << "Россия\t" << capitals["Россия"] << std::endl;
    std::cout << "Северная Корея\t" << capitals["Северная Корея"] << std::endl;
    std::cout << "Китай\t" << capitals["Китай"] << std::endl;

    Весь исходник программы будет выглядеть так:

    #include <iostream>
    #include <map>
    
    int main() {
        std::map<std::string, std::string> capitals;
       
        capitals["Россия"] = "Москва";
        capitals["Северная Корея"] = "Пхеньян";
        capitals["Китай"] = "Пекин";
    
        std::cout << "Россия\t" << capitals["Россия"] << std::endl;
        std::cout << "Северная Корея\t" << capitals["Северная Корея"] << std::endl;
        std::cout << "Китай\t" << capitals["Китай"] << std::endl;
    }

    После запуска этой программы в консоли получим следующее:

    Россия Москва
    Северная Корея Пхеньян
    Китай Пекин

    Еще один способ создания контейнера map

    Так как элементы в словаре имеют тип pair, то можно проинициализировать их таким способом:

    std::map<std::string, std::string> capitals {
            std::pair<std::string, std::string>{"Россия", "Москва"}, std::pair{"Северная Корея", "Пхеньян"}, std::pair{"Китай", "Пекин"}
        };

    Есть возможность сократить инициализацию:

    std::map<std::string, std::string> capitals {
            {"Россия", "Москва"}, {"Северная Корея", "Пхеньян"}, {"Китай", "Пекин"}
        };

    Как видно, последний способ довольно лаконичный и позволяет быстро создать словарь.

    Перебор элементов в контейнере map

    В прошлом примере мы несколько раз использовали cout для вывода содержимого контейнера в консоль. Вместо этого можно использовать cout только один раз. Но для этого придется перебрать элементы контейнера при помощи цикла for. Сделать это можно так:

    for (const auto& [country, capital] : capitals)
            std::cout << country << "\t" << capital << std::endl;

    Или же есть возможность использовать поля first и second для элементов контейнера:

    for (const auto& element : capitals)
            std::cout << element.first << "\t" << element.second << std::endl;

    И в том и в другом случае вывод в консоли будет таким:

    Китай Пекин
    Россия Москва
    Северная Корея Пхеньян

    Следует обратить внимание на то, что порядок элементов изменился. Дело все в том, что элементы выводятся в консоль по возрастанию ключей, но поскольку ключи представляют собой строки, то они сортируются в алфавитном порядке.

    Удаление элементов из контейнера map

    Для удаления элементов из контейнера map существует функция erase. Вот так, например, можно удалить Китай:

    capitals.erase("Китай");

    Если проинициализировать словарь самым коротким способом, который был показан выше, и применить перебор элементов с помощью цикла for, то весь код вместе с удалением Китая будет выглядеть так:

    #include <iostream>
    #include <map>
    
    int main() {
            std::map<std::string, std::string> capitals {
            {"Россия", "Москва"}, {"Северная Корея", "Пхеньян"}, {"Китай", "Пекин"}
        };
    
        capitals.erase("Китай");
    
        for (const auto& element : capitals)
            std::cout << element.first << "\t" << element.second << std::endl;
    }

    В консоли получим следующий вывод:

    Россия  Москва
    Северная Корея  Пхеньян

    Как видим, Китая в этом списке больше нет.

    Проверка наличия элементов в контейнере map

    Для проверки наличия элемента в контейнере map применяются функции count и contains. Функция count возвращает значение 1 в случае, если элемент присутствует в контейнере, и значение 0, если такого элемента нет. Проверим с помощью count наличие России и США в нашем контейнере capitals:

    #include <iostream>
    #include <map>
    
    int main() {
            std::map<std::string, std::string> capitals {
            {"Россия", "Москва"}, {"Северная Корея", "Пхеньян"}, {"Китай", "Пекин"}
        };
    
        std::cout << "Россия\t" << capitals.count("Россия")<< std::endl;
        std::cout << "США\t" << capitals.count("США")<< std::endl;
    }

    Вывод в консоли:

    Россия  1
    США  0

    Функция contains возвращает true, если элемент имеется в контейнере, и false, если такой элемент не найден. Проверим наличие России и США теперь уже с помощью функции contains:

    #include <iostream>
    #include <map>
    
    int main() {
            std::map<std::string, std::string> capitals {
            {"Россия", "Москва"}, {"Северная Корея", "Пхеньян"}, {"Китай", "Пекин"}
        };
    
        std::cout << "Россия\t" << std::boolalpha << capitals.contains("Россия")<< std::endl;
        std::cout << "США\t" << std::boolalpha << capitals.contains("США")<< std::endl;
    }

    Вывод в консоли:

    Россия  true
    США  false

    Определение размера словаря в контейнере map

    Для определения размера контейнера map в C++ есть функция size. Определим с ее помощью размер нашего словаря со странами и их столицами:

    #include <iostream>
    #include <map>
    
    int main() {
        std::map<std::string, std::string> capitals {
            {"Россия", "Москва"}, {"Северная Корея", "Пхеньян"}, {"Китай", "Пекин"}
        };
    
        std::cout << "Размер словаря:\t" << capitals.size() << std::endl;
    }

    Вывод в консоли:

    Размер словаря:  3

    Еще есть функция empty, которая возвращает значение true в случае, если словарь пустой, и значение false, если нет. Применим ее к нашему словарю:

    #include <iostream>
    #include <map>
    
    int main() {
        std::map<std::string, std::string> capitals {
            {"Россия", "Москва"}, {"Северная Корея", "Пхеньян"}, {"Китай", "Пекин"}
        };
    
        std::cout << "Словарь пустой:\t" << std::boolalpha << capitals.empty() << std::endl;
    }

    Понятно, что в нашем случае вывод будет таким:

    Словарь пустой:  false

    Неупорядоченный контейнер map

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

    #include <iostream>
    #include <unordered_map>
    
    int main() {
        std::unordered_map<std::string, std::string> capitals {
            {"Россия", "Москва"}, {"Северная Корея", "Пхеньян"}, {"Китай", "Пекин"}
        };
    
        for (const auto& element : capitals)
            std::cout << element.first << "\t" << element.second << std::endl;
    
    }

    Получим следующий вывод в консоли:

    Китай  Пекин
    Северная Корея  Пхеньян
    Россия  Москва

    Контейнер set в C++

    Контейнеры set по-другому называются множествами. Это коллекции, которые хранят только уникальные элементы, то есть не могут содержать в себе дубликаты. Каждое значение элемента также является и ключом.

    Как создать контейнер set

    Для создания такого контейнера сначала нужно подключить заголовочный файл <set>:

    #include <set>

    Нам понадобится также заголовок <iostream>:

    #include <iostream>

    Далее в функции main создаем множество. Пусть это будет пока еще пустое множество букв латинского алфавита:

    std::set<std::string> letters;

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

    std::set<std::string> letters{"a", "b", "c", "d", "e"};

    Перебор элементов и вывод в консоль

    Чтобы перебрать все элементы контейнера set и вывести их в консоль, очень удобно использовать цикл for:

    for (std::string letter : letters)
        std::cout << letter << "\t";
    std::cout << std::endl;

    Последняя строчка нужна для перехода на новую строку. Весь исходник будет выглядеть следующим образом:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<std::string> letters{"a", "b", "c", "d", "e"};
    
        for (std::string letter : letters)
            std::cout << letter << "\t";
        std::cout << std::endl;
    }

    Вывод в консоли:

    a b c d e

    Добавление элементов в контейнер set

    Для добавления элементов в контейнер set служит функция insert. Добавим еще две буквы в наше множество letters:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<std::string> letters{"a", "b", "c", "d", "e"};
    
        letters.insert("f");
        letters.insert("g");
    
        for (std::string letter : letters)
            std::cout << letter << "\t";
        std::cout << std::endl;
    }

    Получим такой вывод:

    a b c d e f g

    Как уже говорилось в начале этого раздела, в контейнере set могут быть только уникальные элементы. Поэтому, если мы сделаем, например, вот так:

    letters.insert("f");
    letters.insert("g");
    letters.insert("g");
    letters.insert("g");

    То есть попытаемся добавить букву «g» три раза, то все равно получим в консоли вывод из семи букв, как в прошлом примере.

    Удаление элементов из контейнера set

    Во множествах, как и в словарях, для удаления элементов применяется функция erase. Удалим, например, букву «c» из нашего множества letters:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<std::string> letters{"a", "b", "c", "d", "e"};
    
        letters.erase("c");
    
        for (std::string letter : letters)
            std::cout << letter << "\t";
        std::cout << std::endl;
    }

    Вывод в консоли:

    a b d e

    Как видим, элемент успешно удален.

    Проверка наличия элементов в контейнере set

    Проверить наличие элементов в контейнере set можно при помощи функций count и contains. Вот пример проверки с помощью count:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<std::string> letters{"a", "b", "c", "d", "e"};
    
        std::cout << "Элемент d\t" << letters.count("d") << std::endl;
        std::cout << "Элемент j\t" << letters.count("j") << std::endl;
    }

    Вывод в консоли:

    Элемент d 1
    Элемент j 0

    Пример проверки функцией contains:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<std::string> letters{"a", "b", "c", "d", "e"};
    
        std::cout << "Элемент d\t" << std::boolalpha << letters.contains("d") << std::endl;
        std::cout << "Элемент j\t" << std::boolalpha << letters.contains("j") << std::endl;
    }

    В консоли получим:

    Элемент d true
    Элемент j false

    Все работает так же, как и со словарями.

    Определение размера множества

    И здесь тоже применяются те же функции empty и size, которые мы рассматривали в разделе про словари. И применяются они точно так же:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<std::string> letters{"a", "b", "c", "d", "e"};
    
        std::cout << "Пустое множество: " << std::boolalpha << letters.empty() << std::endl;
        std::cout << "Размер множества: " << letters.size() << std::endl;
    }

    В консоли будет следующий вывод:

    Пустое множество: false
    Размер множества: 5

    Неупорядоченный контейнер set

    Контейнер set упорядочивает свои элементы. Если упорядочивание элементов не требуется, то вместо set можно использовать контейнер unordered_set. Этот контейнер практически ничем не отличается от set, кроме того, что содержит неупорядоченные элементы. Пример:

    #include <iostream>
    #include <unordered_set>
    
    int main() {
        std::unordered_set<std::string> letters{"a", "b", "c", "d", "e"};
    
        for (std::string letter : letters)
            std::cout << letter << "\t";
        std::cout << std::endl;
    
    }

    Вывод в консоли:

    e c b d a

    Далее предлагаем вам решить несложную задачу.

    Задание для самостоятельного выполнения

    Дана следующая таблица:

    Преступление и наказаниеФ.Достоевский
    Горе от умаА.Грибоедов
    Евгений ОнегинА.Пушкин
    Мертвые душиН.Гоголь
    Война и мирЛ.Толстой

    В левой колонке содержатся ключи, а в правой — связанные с ними значения. Требуется создать контейнер map из этих данных и вывести его содержимое в консоль. Далее из ключей создайте контейнер set и с помощью соответствующей функции добавьте в него книги «Анна Каренина» и «Вишневый сад». Содержимое контейнера также нужно вывести в консоль.

    Решение

    Для контейнера map код будет таким:

    #include <iostream>
    #include <map>
    
    int main()
    {
        std::map<std::string, std::string> writers
        {
            {"Преступление и наказание", "Ф.Достоевский"}, {"Горе от ума", "А.Грибоедов"}, {"Евгений Онегин", "А.Пушкин"}, {"Мертвые души", "Н.Гоголь"}, {"Война и мир", "А.Толстой"}
        };
    
        for (const auto& element : writers)
            std::cout << element.first << "\t" << element.second << std::endl;
    }

    Вывод в консоли:

    Война и мир  А.Толстой
    Горе от ума  А.Грибоедов
    Евгений Онегин  А.Пушкин
    Мертвые души  Н.Гоголь
    Преступление и наказание  Ф.Достоевский

    Для контейнера set код будет такой:

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<std::string> books{"Преступление и наказание", "Горе от ума", "Евгений Онегин", "Мертвые души", "Война и мир"};
    
        books.insert("Анна Каренина");
        books.insert("Вишневый сад");
    
        for (std::string book : books)
            std::cout << book << "\t";
        std::cout << std::endl;
    }

    Вывод в консоли:

    Анна Каренина   Вишневый сад   Война и мир   Горе от ума   Евгений Онегин   Мертвые души   Преступление и наказание

    Разбор

    Поделиться

    Скопировано
    0 комментариев
    Комментарии