Структуры данных (11 сентября 2017)
- С++
- Неинициализированные переменные, борьба с Warning-ами: -Wall, -Wextra, -Wshadow
- RangeCheckError:
int a[10], x; a[10];
// undefined behavior
- RangeCheckError fix:
vector<int> a; a.at(10); #define _GLIBCXX_DEBUG
- Структуры:
struct T { int a, b; }; T x; x.a; T y = {2, 3}; T z = T {2, 3};
- Указатели:
int b, *a = &b;
. Они же массивы: int *a = new int[n]; a[1] = 3;
- Неасимптотические оптимизации
- cmath: sqrt, sin, cos, atan, ...
- Вызов функции (если оптимизатор не уберёт его). Пример с рекурсией.
- Ввод, вывод (scanf/printf, cin/cout)
- Операции с памятью: new, delete. Работают не за O(1).
- Случайный, а не последовательный доступ к памяти. Пример с проходом по матрице (умножение матриц).
- Деление и взятие по модулю:
a /= b; a %= b;
. Пример с (a+b)%m.
- Быстрый операции: memcpy, strcmp
- Простейшие структуры данных
- Сумма на отрезке. Частичные суммы.
- Массив фиксированного размера
- int a[n];
- Интерфейс: get(i), set(i,x) − O(1)
- Минусы: удаление и добавление в середину за O(n), поиск за O(n)
- Двусвязный список
struct node { node *l, *r; int data; };
struct list { int length; node *head, *tail; }; // пустой список: head = tail = 0
- Интерфейс:
add_front, add_back, del_front, del_back, add_after, del_node
. Всё за O(1).
- Добавим ссылки внутрь:
node* link[]; link[i]
− node добавленный i-й операцией, тогда появляется del(i) за O(1)
- Поиск за O(n), обращение к i-му элементу за O(min(i, n-i))
- Пишем код поиска x:
Node *p = head; while (p && p->x != x) p = p->next;
- Односвязный список
struct node { node *next; int data; }; node *head = 0;
- Версия на массиве:
struct node { int next, data; } a[n]; int head = -1;
- Пишем код добавления в начало для обеих версий:
head = new Node {head, x};
− Перерыв −
- Расширяющийся массив (вектор)
int size, an, a[size];
- get(i), set(i, x), del_back() − O(1)
- add_back() − O(1) в среднем, доказательство
- C++:
vector<int> a; a.push_back(x), a.pop_back(x)
- Стек, очередь, дек
- Стек :
add_back = push, del_back = pop
за O(1), stack<int>
- Очередь :
add_front = push, del_back = pop
за O(1), queue<int>
- Дек :
add_front, add_back, del_front, del_back
за O(1), deque<int>
- Реализация на двусвязном списке
- Реализация стека, очереди, дека на динамическом массиве
- Реализация стека, очереди, дека на циклическом массиве
- Сравнение двусвязного списка и очереди.
- Очередь и стек с минимумом
- Стек с минимумом: частичные минимумы
- Очередь с минимумом через два стека:
Q = <S, S>
, push = O(1), pop = O(1) + reverse iff need
- Амортизированное время работы
- Определение через потенциальную функцию: ai = ti + Δφ (пример: вектор)
- Определение через монетки: есть операции, которые накапливают средства (Δφ > 0), а есть те, что тратят (Δφ < 0). (пример: вектор)