Множества (Set) в C++17: подробное руководство
Что такое Множества (Set)?
Представь себе коробку для хранения уникальных игрушек. Если ты попытаешься положить туда два одинаковых мячика, то второй мячик просто не поместится — в коробке уже есть такой же.
В C++ такой «коробкой» для данных является std::set. Это коллекция, которая хранит элементы только в единственном экземпляре и автоматически сортирует их по возрастанию.
Зачем это нужно? Например, чтобы:
- Убрать дубликаты из списка (оставить только уникальные товары).
- Проверить, есть ли элемент в коллекции (записан ли контакт в книжку).
- Объединить два списка без повторов (список покупок от двух друзей).
Как подключить и объявить set?
Чтобы использовать set, нужно подключить библиотеку #include <set>.
#include <iostream>
#include <set> // Подключаем множества
#include <string>
int main() {
// Создаем множество строк
std::set<std::string> ingredients;
// Создаем множество целых чисел
std::set<int> numbers;
return 0;
}
Как добавить элемент?
Используем метод .insert(). Если элемент уже есть, он не добавится повторно.
#include <iostream>
#include <set>
int main() {
std::set<int> mySet;
mySet.insert(10);
mySet.insert(5);
mySet.insert(10); // Этот элемент не добавится, так как 10 уже есть!
mySet.insert(3);
// Выведем все элементы (они будут отсортированы)
for(int num : mySet) {
std::cout << num << " ";
}
// Вывод: 3 5 10
return 0;
}
Как проверить, есть ли элемент?
Метод .count() возвращает 1 (если элемент есть) или 0 (если нет).
#include <iostream>
#include <set>
#include <string>
int main() {
std::set<std::string> contacts = {"Аня", "Борис", "Вика"};
std::string name;
std::cout << "Введите имя для поиска: ";
std::cin >> name;
if(contacts.count(name) == 1) {
std::cout << "Контакт найден!";
} else {
std::cout << "Контакта нет в книжке.";
}
return 0;
}
Как удалить элемент?
Метод .erase() удаляет элемент по значению.
#include <iostream>
#include <set>
int main() {
std::set<std::string> shopping = {"молоко", "хлеб", "яйца", "сыр"};
std::string item;
std::cout << "Что хотите убрать из списка? ";
std::cin >> item;
shopping.erase(item); // Удаляем элемент
std::cout << "Осталось в списке: ";
for(const auto& thing : shopping) {
std::cout << thing << " ";
}
return 0;
}
Как узнать размер множества?
Метод .size() возвращает количество элементов.
#include <iostream>
#include <set>
int main() {
std::set<int> numbers = {1, 2, 3, 4, 5, 5, 5}; // Повторы не считаются
std::cout << "Размер множества: " << numbers.size(); // Вывод: 5
return 0;
}
Разбор типичных задач
Задача 1. Уникальные ингредиенты пиццы
Пользователь вводит ингредиенты через запятую. Нужно вывести только уникальные.
#include <iostream>
#include <set>
#include <sstream> // Для работы со строками
#include <string>
int main() {
std::string input;
std::cout << "Введите ингредиенты через запятую: ";
std::getline(std::cin, input);
std::set<std::string> uniqueIngredients;
std::stringstream ss(input);
std::string ingredient;
// Разделяем строку по запятым
while(std::getline(ss, ingredient, ',')) {
// Убираем лишние пробелы в начале и конце
if(!ingredient.empty() && ingredient[0] == ' ') {
ingredient = ingredient.substr(1);
}
if(!ingredient.empty()) {
uniqueIngredients.insert(ingredient);
}
}
std::cout << "Уникальные ингредиенты: ";
for(const auto& item : uniqueIngredients) {
std::cout << item << " ";
}
return 0;
}
Задача 2. Объединение списков покупок
Есть два списка покупок. Нужно их объединить без повторов.
#include <iostream>
#include <set>
#include <string>
int main() {
std::set<std::string> mainList = {"кола", "чипсы", "пицца"};
std::set<std::string> guestList = {"сок", "чипсы", "орешки"};
// Добавляем элементы из второго списка в первый
for(const auto& item : guestList) {
mainList.insert(item);
}
std::cout << "Финальный список покупок: ";
for(const auto& product : mainList) {
std::cout << product << " ";
}
// Вывод: кола орешки пицца сок чипсы (все уникально и отсортировано)
return 0;
}
Частые ошибки новичков
- Путают set с vector. В set нельзя обратиться по индексу (
mySet[0]— ошибка). Используйте циклforили итераторы. - Забывают про #include <set>. Без этой строки компилятор не поймет, что такое
std::set. - Думают, что insert добавит элемент, даже если он есть. Нет,
insertне создает дубликатов. Если нужно хранить повторы — используйтеstd::multiset. - Пытаются изменить элемент в set. Элементы в set — константные. Нельзя написать
*it = 5;. Сначала удалите старый, потом добавьте новый.
Итоговый пример: Записная книжка контактов
Создадим программу, которая хранит имена контактов (только уникальные) и позволяет их искать.
#include <iostream>
#include <set>
#include <string>
int main() {
std::set<std::string> phoneBook;
std::string command;
std::cout << "Записная книжка контактов\n";
std::cout << "Команды: add Имя, find Имя, list, exit\n";
while(true) {
std::cout << "> ";
std::cin >> command;
if(command == "add") {
std::string name;
std::cin >> name;
phoneBook.insert(name);
std::cout << "Контакт \"" << name << "\" добавлен.\n";
}
else if(command == "find") {
std::string name;
std::cin >> name;
if(phoneBook.count(name) == 1) {
std::cout << "Контакт \"" << name << "\" найден.\n";
} else {
std::cout << "Контакт не найден.\n";
}
}
else if(command == "list") {
std::cout << "Все контакты:\n";
for(const auto& contact : phoneBook) {
std::cout << "- " << contact << "\n";
}
}
else if(command == "exit") {
break;
}
else {
std::cout << "Неизвестная команда.\n";
}
}
return 0;
}
Вывод программы:
Записная книжка контактов
Команды: add Имя, find Имя, list, exit
> add Маша
Контакт "Маша" добавлен.
> add Петя
Контакт "Петя" добавлен.
> add Маша
Контакт "Маша" добавлен. (Но в set он уже был, поэтому ничего не изменилось)
> list
Все контакты:
- Маша
- Петя
> exit
Множества (set) — это мощный инструмент для работы с уникальными данными. Они автоматически сортируют элементы и не допускают дубликатов. Используй их, когда нужно быстро проверить наличие элемента или избавиться от повторений!