Структуры данных (25 сентября 2024)
- [20 минут] Избавляемся от амортизации
- Вектор. Ленивое копирование: когда переполнились начинаем копировать по одному элементу
- Вектор. Ленивое копирование: заранее начинаем копировать по одному элементу и выделять память
- Хеш-таблица. Ленивое копирование.
- Очередь с минимумом на двух стеках (тоже избавляемся от амортизации). Реализация через два динамических массива.
- [25 минут] Куча
- Вводная задача: есть дела, у них есть приоритеты; появляются новые дела, нужно иногда делать наиболее приоритетную задачу.
- Интерфейс (базовый): add, extractMin; интерфейс (расширенный): del, decreaseKey.
- Бинарная куча: реализация на массиве через siftUp → decreaseKey, add; siftDown → extractMin, del
- Бинарная куча: build за O(n) (док-во sum k/2k уже было в практике)
- Обратные ссылки (пример: массив с операциями a[i]=x, min на всём массиве, вводная задача: у i-го дела иногда меняется приоритет)
- Min = Max (+1 на -1, меньше на больше)
- heapsort = build + ExtractMin*n
- Преобразование операций: decreaseKey = del + add; del = decreaseKey + exractMin
− Перерыв −
- [22 минут] Пополняемые структуры данных. Преобразование операций.
- Find → Del. Удалить X из структуры, умеющей только Find : пометить, как удалённый. (пример из прошлого: хеш-таблица с открытой адресацией)
- Учим
priority_queue
делать Del: храним отдельно две кучи − добавленные элементы, удалённые элементы.
- Add → Merge. Сливаемые структуры: меньшее к большему (учим кучи и хеш-таблицы сливаться)
- Merge → Add. Add − просто частный случай Merge.
- Build → Add. Пополняемый массив: добавить X, посчитать количество X от L до R.
- [5 минут] Корневая. Предподсчёт за O(nlogn), добавление за O(n1/2), запрос за 2logn.
- [10 минут] Предподсчёт за O(nlogn), запрос за log2n. Добавление нового элемента = пополняемые структуры.
- Build → Add → Del. Удалить X из структуры с аддитивным запросом (хранить две структуры = добавленные элементы + удалённые)
- [15 минут] Аллокация памяти
- Общие слова: в C++ память откуда-то берётся. Локальное на стеке, глобальное и через new из heap-а. Научимся делать что-то такое же ручками, иногда эффективнее.
- [5 минут] Стек + рекурсия (освобождать можно только последнее выделенное). Доп.пример: когда пишем на c++ можно в деструктор засунуть финализатор и дёрнуть из него наш delete.
- [5 минут] Список + куски одного размера (пример: двусвязный список, хеш-таблица на списках) + кеширование
- [5 минут] Сложное решение общей задачи аллокации (только идея, без технические подробностей): куча свободных кусков и указатели на следующий/предыдущий.
- В с++ : new = наш аллокатор, delete = empty
- [skipped] [10 минут] Два указателя и ответы на запросы в offline
- [skipped] Число различных чисел на отрезке li ≤ li+1, ri ≤ ri+1. O(n+m).
- [skipped] Отрезки произвольны. Алгоритм Мо. O(nm1/2).