Контейнеры STL
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 71 из 104.
Контейнеры STL — это шаблонные классы, которые хранят и организуют коллекции объектов. Каждый тип контейнера оптимизирован для различных шаблонов доступа и операций. Выбор подходящего контейнера для ваших нужд может существенно повлиять на производительность вашей программы.
Последовательные контейнеры поддерживают элементы в определенном порядке:
#include <vector>
#include <list>
std::vector<int> vec = {1, 2, 3}; // Динамический массив, быстрый произвольный доступ
vec.push_back(4); // Добавление в конец: O(1) амортизированное
int x = vec[2]; // Доступ по индексу: O(1)
std::list<int> lst = {1, 2, 3}; // Двусвязный список
lst.push_front(0); // Добавление в начало: O(1)
lst.push_back(4); // Добавление в конец: O(1)Ассоциативные контейнеры хранят элементы в отсортированном порядке для быстрого поиска:
#include <map>
#include <set>
std::set<int> s = {3, 1, 4, 1}; // Уникальные отсортированные элементы: {1, 3, 4}
s.insert(2); // Вставка: O(log n)
bool found = s.count(3); // Проверка существования: O(log n)
std::map<std::string, int> ages; // Пары ключ-значение, отсортированные по ключу
ages["Alice"] = 25; // Вставка/обновление: O(log n)
ages["Bob"] = 30;
std::cout << ages["Alice"]; // Доступ: O(log n)Неупорядоченные контейнеры используют хеш-таблицы для еще более быстрого поиска в среднем случае:
#include <unordered_map>
std::unordered_map<std::string, int> scores;
scores["player1"] = 100; // Вставка: O(1) в среднем
scores["player2"] = 200;
std::cout << scores["player1"]; // Доступ: O(1) в среднемИспользуйте vector, когда вам нужен быстрый произвольный доступ, list для частых вставок в середину, map/set, когда вам нужны отсортированные данные, и unordered_map, когда скорость поиска критична, а порядок не имеет значения.
Задание
ЛегкоДавайте создадим систему управления оценками студентов, которая продемонстрирует, как различные контейнеры STL служат разным целям. Вы будете использовать несколько типов контейнеров для эффективной организации данных о студентах, выбирая подходящий контейнер для каждой задачи.
Для организации кода вы создадите два файла:
GradeManager.h: Определите классGradeManager, который использует несколько контейнеров STL для управления информацией о студентах.Ваш класс должен использовать:
std::vector<std::string>для хранения имен студентов в порядке их добавленияstd::map<std::string, int>для связывания имени каждого студента с его оценкойstd::set<int>для отслеживания всех уникальных оценок, которые были выставлены
Реализуйте следующие методы:
addStudent(const std::string& name, int grade)— добавляет студента с его оценкой во все три контейнераgetGrade(const std::string& name)— возвращает оценку для заданного имени студента, используя mapprintRoster()— выводит все имена студентов в порядке их добавления (из вектора), каждое на новой строкеprintGrades()— выводит всех студентов с их оценками в алфавитном порядке (map делает это автоматически), в форматеname: gradeна каждой строкеprintUniqueGrades()— выводит все уникальные оценки в порядке возрастания (set делает это автоматически), разделенные пробелами, после чего следует символ новой строки
main.cpp: Считайте входные данные и продемонстрируйте, как каждый тип контейнера служит своей цели.Считайте шесть входных значений (каждое на отдельной строке):
- Имя первого студента
- Оценка первого студента (целое число)
- Имя второго студента
- Оценка второго студента (целое число)
- Имя третьего студента
- Оценка третьего студента (целое число)
Создайте объект
GradeManagerи добавьте всех трех студентов. Затем продемонстрируйте различное поведение контейнеров:- Выведите
Roster (insertion order):, а затем вызовитеprintRoster() - Выведите
Grades (alphabetical):, а затем вызовитеprintGrades() - Выведите
Unique grades:, а затем вызовитеprintUniqueGrades() - Найдите оценку второго студента и выведите
<name>'s grade: <grade>
Например, при входных данных Charlie, 85, Alice, 90, Bob, 85:
Roster (insertion order):
Charlie
Alice
Bob
Grades (alphabetical):
Alice: 90
Bob: 85
Charlie: 85
Unique grades:
85 90
Alice's grade: 90Обратите внимание, как вектор сохраняет порядок вставки (Charlie, Alice, Bob), map автоматически сортирует по ключу (Alice, Bob, Charlie), а set хранит только уникальные значения в отсортированном порядке (85 появляется один раз, а не два). Каждый тип контейнера отлично справляется с определенными задачами!
Шпаргалка
Контейнеры STL — это шаблонные классы для хранения и организации коллекций объектов. Каждый тип оптимизирован для различных операций.
Последовательные контейнеры
Поддерживают элементы в определенном порядке:
#include <vector>
#include <list>
std::vector<int> vec = {1, 2, 3}; // Динамический массив, быстрый произвольный доступ
vec.push_back(4); // Добавление в конец: O(1) амортизированное
int x = vec[2]; // Доступ по индексу: O(1)
std::list<int> lst = {1, 2, 3}; // Двусвязный список
lst.push_front(0); // Добавление в начало: O(1)
lst.push_back(4); // Добавление в конец: O(1)Ассоциативные контейнеры
Хранят элементы в отсортированном порядке для быстрого поиска:
#include <map>
#include <set>
std::set<int> s = {3, 1, 4, 1}; // Уникальные отсортированные элементы: {1, 3, 4}
s.insert(2); // Вставка: O(log n)
bool found = s.count(3); // Проверка существования: O(log n)
std::map<std::string, int> ages; // Пары ключ-значение, отсортированные по ключу
ages["Alice"] = 25; // Вставка/обновление: O(log n)
ages["Bob"] = 30;
std::cout << ages["Alice"]; // Доступ: O(log n)Неупорядоченные контейнеры
Используют хеш-таблицы для более быстрого поиска в среднем случае:
#include <unordered_map>
std::unordered_map<std::string, int> scores;
scores["player1"] = 100; // Вставка: O(1) в среднем
scores["player2"] = 200;
std::cout << scores["player1"]; // Доступ: O(1) в среднемВыбор подходящего контейнера
vector: Быстрый произвольный доступlist: Частые вставки в серединуmap/set: Необходимы отсортированные данныеunordered_map: Скорость поиска критична, порядок не имеет значения
Попробуйте сами
#include <iostream>
#include <string>
#include "GradeManager.h"
using namespace std;
int main() {
// Считать входные данные для трех студентов
string name1, name2, name3;
int grade1, grade2, grade3;
cin >> name1;
cin >> grade1;
cin >> name2;
cin >> grade2;
cin >> name3;
cin >> grade3;
// TODO: Создать объект GradeManager
// TODO: Добавить всех трех студентов в GradeManager
// TODO: Вывести "Roster (insertion order):" и вызвать printRoster()
// TODO: Вывести "Grades (alphabetical):" и вызвать printGrades()
// TODO: Вывести "Unique grades:" и вызвать printUniqueGrades()
// TODO: Найти оценку второго студента и вывести "<name>'s grade: <grade>"
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер