C++ Структуры данных
C++ предоставляет множество структур данных — от базовых, таких как массивы, структуры и классы, до продвинутых контейнеров STL, таких какvector、mapиunordered_mapи т. д.
Ниже подробно описаны часто используемые структуры данных в C++, а также их особенности и применение.
1. Массив
Массивы — это самые базовые структуры данных, используемые для хранения набора данных одного типа.
Особенности:
- Фиксированный размер; после объявления размер нельзя изменить.
- Прямой доступ к элементам с временной сложностью O(1).
- Подходит для обработки коллекций известного размера с одинаковыми типами элементов.
Пример
cout << arr[0]; // Вывод первого элемента
Преимущества и недостатки:
- Преимущество: высокая скорость доступа, компактное использование памяти.
- Недостатки: фиксированный размер, невозможно динамически расширять, не подходит для наборов данных неизвестного размера.
2. Структура
Структуры позволяют объединять данные разных типов для формирования пользовательского типа данных.
Особенности:
- Может содержать переменные-члены разных типов.
- Обеспечивает базовую инкапсуляцию данных, но с ограниченной функциональностью.
Пример:
Пример
string name;
int age;
};
Person p = {"Alice", 25};
cout << p.name << endl; // Вывод Alice
3. Класс
Классы — это основная структура для объектно-ориентированного программирования в C++, позволяющая определять переменные-члены и функции-члены. По сравнению сstructПохожи, но более мощные, поддерживают такие возможности, как наследование, инкапсуляция и полиморфизм.
Особенности:
- Может включать переменные-члены, функции-члены, конструкторы и деструкторы.
- Поддерживает объектно-ориентированные возможности, такие как инкапсуляция, наследование и полиморфизм.
Пример
private:
string name;
int age;
public:
Person(string n, int a) : name(n), age(a) {}
void printInfo() {
cout << "Имя: " << name << ", Возраст: " << age << endl;
}
};
Person p("Bob", 30);
p.printInfo(); // Вывод: Имя: Bob, Возраст: 30
4. Связный список
Связный список — это динамическая структура данных, состоящая из последовательности узлов, каждый из которых содержит данные и указатель на следующий узел.
Особенности:
- Динамически изменяет размер, нет необходимости заранее задавать вместимость.
- Операции вставки и удаления эффективны, временная сложность — O(1) (при работе с головой или хвостом списка).
- Линейный поиск с временной сложностью O(n).
Пример (односвязный список)
int data;
Node* next;
};
Node* head = nullptr;
Node* newNode = new Node{10, nullptr};
head = newNode; // Вставить новый узел
Преимущества и недостатки:
- Преимущества: динамический размер, подходит для сценариев с частыми вставками и удалениями.
- Недостатки: неэффективный произвольный доступ, не так быстр, как прямой доступ к массиву.
5. Стек
Стек — это структура данных «последним пришёл — первым вышел» (LIFO), обычно используется в таких сценариях, как рекурсия и поиск в глубину.
Особенности:
- Разрешает операции вставки и удаления только на вершине стека.
- Временная сложность — O(1).
Пример
s.push(1);
s.push(2);
cout << s.top(); // Вывод 2
s.pop();
Преимущества и недостатки:
- Преимущество: простые операции, высокая эффективность.
- Недостатки: операции можно выполнять только на вершине; для доступа к другим элементам требуется извлечь верхний элемент.
6. Очередь
Очередь — это структура данных «первым пришёл — первым вышел» (FIFO), обычно используемая в таких сценариях, как поиск в ширину и планирование задач.
Особенности:
- Операции вставки выполняются в хвосте очереди, а операции удаления — в голове.
- Временная сложность — O(1).
Пример
q.push(1);
q.push(2);
cout << q.front(); // Вывод 1
q.pop();
Преимущества и недостатки:
- Преимущества: подходит для сценариев, в которых данные обрабатываются в порядке поступления, например для планирования задач.
- Недостаток: невозможен произвольный доступ к элементам.
7. Двусторонняя очередь (Deque)
deque позволяет выполнять операции вставки и удаления на обоих концах, объединяя возможности стека и очереди.
Особенности:
- Позволяет выполнять вставку и удаление на обоих концах.
- Временная сложность — O(1).
Пример
dq.push_back(1);
dq.push_front(2);
cout << dq.front(); // Вывод 2
dq.pop_front();
Преимущества и недостатки:
- Преимущество: гибкие двунаправленные операции.
- Недостатки: большее использование пространства, подходит для сценариев, требующих частых операций на обоих концах.
8. Хеш-таблица
Хеш-таблица — это структура данных, которая хранит данные в виде пар ключ-значение, поддерживая быстрый поиск, вставку и удаление. В C++,unordered_mapРеализация хеш-таблицы.
Особенности:
- Использует хеш-функцию для быстрого поиска элементов; временная сложность — O(1).
- Не гарантирует порядок элементов.
Пример
hashTable["apple"] = 10;
cout << hashTable["apple"]; // Вывод 10
Преимущества и недостатки:
- Преимущества: высокая эффективность операций поиска, вставки и удаления.
- Недостатки: не гарантирует порядок элементов, а производительность снижается при возникновении хеш-коллизий.
9. Map
mapЭто упорядоченный контейнер пар ключ-значение, реализованный с помощью красно-чёрного дерева. По сравнению сunordered_mapВ отличие от него, он гарантирует порядок ключей; временная сложность поиска, вставки и удаления — O(log n).
Особенности:
- Гарантирует, что элементы упорядочены по их ключам.
- Реализован с помощью двоичного дерева поиска.
Пример
myMap["apple"] = 10;
cout << myMap["apple"]; // Вывод 10
Преимущества и недостатки:
- Преимущества: элементы упорядочены, подходит для сценариев, в которых необходимо обрабатывать данные по порядку.
- Недостаток: более низкая производительность, чем
unordered_mapНемного ниже.
10. Set
setЭто упорядоченное множество для хранения уникальных элементов, также реализованное с помощью красно-чёрного дерева. Оно гарантирует, что элементы не дублируются и упорядочены.
Особенности:
- Гарантирует уникальность элементов.
- Элементы автоматически располагаются в порядке возрастания.
- Временная сложность — O(log n).
Пример
s.insert(1);
s.insert(2);
cout << *s.begin(); // Вывод 1
Преимущества и недостатки:
- Преимущество: автоматическая сортировка и гарантия уникальности.
- Недостатки: эффективность вставки и удаления ниже, чем у неупорядоченных множеств.
11. Динамический массив (вектор)
vectorЭто реализация динамического массива, предоставляемая стандартной библиотекой C++, которая может динамически расширять вместимость и поддерживает произвольный доступ.
Особенности:
- Динамическое изменение размера.
- Поддерживает произвольный доступ с временной сложностью O(1).
- Когда ёмкости недостаточно, он динамически расширяется, с амортизированной временной сложностью O(1).
Пример
v.push_back(1);
v.push_back(2);
cout << v[0]; // Вывод 1
Преимущества и недостатки:
- Преимущества: поддерживает произвольный доступ и динамическое расширение.
- Недостатки: низкая эффективность при вставке или удалении элементов в середине.