1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7

# конспект · шаг 7 из 7

Конспект: амортизированный анализ

выжимка - её можно унести в заметки

Понятия

Амортизированная цена - средняя цена операции по СЕРИИ из n операций в худшем случае, без вероятности. Гарантия по любой серии, даже худшей (этим отличается от среднего случая - ожидания по случайным входам).

Агрегатный метод - посчитать общую цену серии T(n) и поделить на n: амортизированная цена = T(n)/n.

Метод предоплаты (учётный) - назначить операции цену ĉ; переплата копится кредитом, дорогие операции платят из него; кредит всегда ≥ 0, тогда Σĉ ≥ Σc.

Метод потенциалов - функция Φ(D) ≥ 0 от состояния, Φ(D₀) = 0; амортизиро‐ ванная цена ĉ = c + Φ(после) − Φ(до). При суммировании средние Φ телескопируются: Σĉ = Σc + Φ(D_n) ≥ Σc.

Динамический массив - буфер, который удваивается при заполнении и копирует старое. num занято, size ёмкость, коэффициент заполнения num/size.

Что унести

Три метода дают одну оценку. Агрегатный - грубее и сразу на всю серию; предоплата и потенциал считают цену каждой операции и не требуют знать серию наперёд. Кредит предоплаты и значение Φ - одно и то же число: накопленный про запас ресурс.

Вставка в динамический массив - O(1) амортизированно. Потенциал Φ = 2·num − size («заполнение сверх половины»): обычная вставка поднимает Φ на 2, цена 1 + 2 = 3; вставка с удвоением (num = size = s) копирует s, но Φ падает с s до 2, цена (s+1) + 2 − s = 3. Запас копится при заполнении и тратится на удвоении.

С удалениями нужен ЗАЗОР между порогами: удваивать при заполнении 1, ужимать вдвое ниже 1/4. Сжатие при 1/2 даёт качели у границы - Θ(n) на операцию. Потенциал из двух ветвей: 2·num − size выше половины, size/2 − num ниже; обе равны нулю при α = 1/2.

Удвоение принципиально. Рост на постоянные +c даёт n/c перестроек и c + 2c + ... = Θ(n²) копирований (арифметический ряд) - вставка Θ(n). Удвоение даёт 1 + 2 + 4 + ... + n < 2n = Θ(n) (геометрический ряд) - вставка O(1). Тот же геометрический ряд стоит за агрегатным доказательством и за двоичным счётчиком (O(1) на увеличение, не Θ(log n)).

Стек с multipop - канонический пример: Φ = высота стека, push стоит 2, pop и multipop(k) - 0 (гасятся падением Φ). Дорогой multipop бесплатен амортизированно, потому что его заранее оплатили push-и.

Это внутренность list/ArrayList/vector: append - O(1) амортизированно, а склейка строки в цикле (s = s + c) - Θ(n²), потому что строку нельзя дописать на месте, её копируют целиком.

Ловушки джокера

Спутал амортизацию со средним случаем. Амортизация не знает вероятностей: гарантия по любой серии, а не по удаче. «В среднем O(1), но на плохом входе O(n)» - это НЕ амортизация.

Взял максимум по одной операции. Объявить вставку Θ(n) (по удвоению) и серию Θ(n²) - завышение: дорогие удвоения редки, серия Θ(n).

В предоплате не проверил кредит. Если дорогая операция раньше накопления, кредит уходит в минус, и «предоплата» ничего не доказывает.

Взял Φ с отрицательными значениями или ненулевым стартом. Тогда Φ(конец) − Φ(старт) бывает отрицательным, Σĉ < Σc, оценка перестаёт быть верхней.

Сжал буфер на том же пороге, на котором расширял. Массив у границы перестраивается на каждой второй операции; порог сжатия - 1/4, а не 1/2.

Нарастил буфер на константу ради памяти. Сэкономишь память, но вставка станет Θ(n) амортизированно, а построение массива - Θ(n²).

Проверь себя

Чем амортизированная цена отличается от среднего случая?

Как считают амортизированную цену тремя методами (агрегатным, предоплатой, потенциалом)?

Зачем в методе потенциалов нужны Φ ≥ 0 и Φ(D₀) = 0?

Почему вставка в динамический массив O(1) амортизированно и при чём тут Φ = 2·num − size?

Почему буфер удваивают, а не наращивают на константу?

Почему list.append считают O(1), а склейку строки в цикле - Θ(n²)?

Почему буфер ужимают при заполнении ниже 1/4, а не ниже 1/2?

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.