Амортизированный анализ? (Гарантия исполнения в худшем случае)

13

Что такое амортизированный анализ? И как это может помочь мне достичь наихудших гарантий производительности в моих программах?

Я читал, что следующие методы могут помочь программисту достичь гарантий производительности в худшем случае (то есть, по моим собственным словам: гарантировать, что время выполнения программы не превысит время выполнения в худшем случае):

  • Рандомизированные алгоритмы (например, алгоритм быстрой сортировки является квадратичным в наихудшем случае, но случайное упорядочение входных данных дает вероятностную гарантию того, что время его работы является линейным)
  • Последовательности операций (наш анализ должен учитывать как данные, так и последовательность операций, выполняемых клиентом)
  • Амортизированный анализ (еще один способ предоставления гарантии производительности - амортизация стоимости путем отслеживания общей стоимости всех операций, деленной на количество операций. В этом параметре мы можем разрешить некоторые дорогостоящие операции, сохраняя при этом среднюю стоимость операций на низком уровне. Другими словами, мы распределяем стоимость нескольких дорогостоящих операций, назначая часть их каждой из большого количества недорогих операций).

Автор упомянул использование структуры данных массива изменения размеров для стека в качестве одного из примеров того, как выполнить амортизированный анализ, но я до сих пор не понимаю, что такое амортизированный анализ и как его можно реально реализовать (структура данных? Алгоритм?) Для достижения худшего гарантия исполнения

Энтони
источник

Ответы:

14

Вы не применяете амортизированный анализ. Это методика получения более точных Oграниц.

Существенное наблюдение, которое вы должны сделать, состоит в том, что дорогостоящие операции не могут происходить в любое время.

В случае структуры данных на основе массива, массив требует изменения размера время от времени - когда он заполнен. Это самая дорогая операция и занимает много O(n)времени. Все остальные вставки в массив есть O(1).

Чтобы определить время выполнения для вставки nэлементов, вы можете умножить nна самую дорогую операцию O(n), что приводит к общему поведению во время выполнения O(n^2).

Тем не менее, это неточно, потому что изменение размера не может происходить очень часто.

Говоря о деньгах, вы амортизируете стоимость, когда со временем оплачиваете свой долг несколькими небольшими платежами.

Мы можем использовать эту модель, чтобы думать об алгоритмах. Мы просто заменяем «время» на «деньги», чтобы избежать ментального отображения.

Как только массив заполнен до его длины n, мы можем удвоить его размер. Нам нужно сделать следующие операции:

  • Выделите 2nкуски памяти
  • копировать nпредметы

Если предположить, что выделение памяти и копирование происходят за линейное время, это будет очень дорогая операция. Однако теперь мы можем использовать идею долга и амортизировать ее для нашего анализа. Только мы собираемся амортизировать наш долг, прежде чем мы действительно сделаем это.
Давайте предположим, что наш баланс (денег / времени) вернулся к 0 (т.е. у нас нет долгов и нет остатков) после изменения размера массива.

Это имеет следующее значение:

  • Вставка следующих nэлементов покроет стоимость изменения размера и копирования (мы nиспользовали слоты и nнеиспользуемые слоты)

Теперь мы можем думать о том, сколько должна заплатить каждая операция вставки:

  • Вставка
  • Стоимость выделения одного куска памяти
  • стоимость перемещения его во вновь выделенную память

Теперь мы покрыли расходы на выделение памяти, копирование и вставку следующих nэлементов. Тем не менее, мы еще не забыли выделить место для старых nэлементов, а также скопировать их.

Мы просто распределяем стоимость наших старых nэлементов на наши новые (еще не вставленные) nэлементы:

  • Стоимость выделения одного куска памяти
  • стоимость перемещения его во вновь выделенную память

В общей сложности каждая операция вставки будет стоить 5 единиц. Это платит за собственную вставку, а также перемещение и выделение места для себя и одного из старых элементов.

Каждая операция вставки все еще занимает постоянное количество времени, но изменение размера происходит бесплатно: мы амортизируем ее, затрачивая «больше» времени на каждую вставку.

В результате вставка nэлементов занимает много O(n)времени.

Другие методы амортизированного анализа объясняются здесь .

phant0m
источник
1

Прежде всего: это метод анализа времени выполнения программы, а не метод реализации алгоритмов.

Хороший пример, упомянутый в вашем списке: добавление одного элемента в структуру данных на основе массива. Для каждой операции добавления в худшем случае необходимо скопировать все существующие элементы. Такой анализ слишком пессимистичен, так как вам не нужно этого делать, если вы используете разумную стратегию изменения размера (умножение размера на некоторое x> 1,0). Затем анализ говорит, что у вас есть предел O (n ^ 2) - O (n) на элемент, умноженный на n элементов, в то время как фактическое время выполнения - только O (n).

Если вы усредняете стоимость изменения размера по всем вставленным элементам (большинство из которых не требуют изменения размера), вы выполняете амортизированный анализ. Амортизированный анализ приводит к ограничению O (n), которое соответствует фактическому поведению алгоритма.

Патрик
источник