Как выбрать контейнер
Узнать, есть ли число в векторе, можно только перебором: цикл сравнивает с этим числом каждый элемент. std::set отвечает на тот же вопрос одним вызовом contains:
#include <iostream>
#include <set>
#include <vector>
int main() {
std::vector<int> v{7, 3, 9};
bool in_vector = false;
for (int x : v) {
if (x == 9) {
in_vector = true;
}
}
std::set<int> s{7, 3, 9};
std::cout << in_vector << ' ' << s.contains(9) << '\n'; // 1 1
}Для трёх чисел разницы не видно. Но перебор миллиона элементов делает до миллиона сравнений, а std::set находит ключ среди миллиона за несколько десятков. Контейнер выбирают по тому, что программа делает с данными чаще всего.
Вектор по умолчанию
Начинайте с std::vector. Он хранит элементы подряд, в порядке добавления, допускает повторы и даёт доступ по индексу. Добавление в конец и обход у него быстрые. Медленно только искать значение: время поиска растёт вместе с размером.
Если ключи — числа подряд от 0, вектор заменяет и std::map: индекс работает как ключ. Например, счётчики оценок от 0 до 5 помещаются в std::vector<int> из шести элементов.
Ключи и поиск
std::map и std::set подходят, когда ключи уникальны и нужен их порядок. Чтобы держать вектор упорядоченным, каждое новое значение пришлось бы вставлять в нужное место, сдвигая остальные. std::map и std::set сохраняют порядок сами при каждой вставке.
Время поиска в них растёт очень медленно: удвоение размера добавляет одно-два сравнения. std::set помнит, какие значения уже встречались, а std::map хранит данные по ключу, например счётчики.
Если порядок ключей не нужен, а искать приходится часто, берите std::unordered_map. В среднем он находит ключ за одно и то же время при любом размере. Ключом может быть число или std::string: хеш для них уже определён.
| Задача | Контейнер |
|---|---|
| хранить по порядку, обращаться по индексу | std::vector |
| помнить уникальные значения | std::set |
| хранить значения по ключу, ключи по порядку | std::map |
| хранить значения по ключу, порядок не важен | std::unordered_map |
Частая ошибка
Ключи std::unordered_map выводят, ожидая порядка по алфавиту:
std::unordered_map<std::string, int> stock{ // ✗
{"pear", 2}, {"apple", 7}, {"kiwi", 5}};
for (const auto& item : stock) {
std::cout << item.first << ' ';
}Порядок обхода std::unordered_map стандарт не задаёт: он зависит от реализации и может меняться после новых вставок. Если ключи нужны по порядку, возьмите std::map: его цикл выведет apple kiwi pear. Заменить нужно только тип и заголовок, остальной код останется прежним.