Как реализовать алгоритм Прима с кучей Фибоначчи?
Я знаю алгоритм Прима и знаю его реализацию, но всегда пропускаю часть, которую хочу сейчас спросить. Было написано, что реализация алгоритма Прима с кучей Фибоначчи O(E + V log(V))
и мой вопрос:
- что такое куча Фибоначчи?
- Как это реализовано? А также
- Как вы можете реализовать алгоритм Прима с кучей Фибоначчи?
3 ответа
Куча Фибоначчи - это довольно сложная очередь с приоритетами, которая имеет отличное амортизированное асимптотическое поведение для всех своих операций - вставка, поиск-мин и ключ уменьшения - все выполняются за время амортизации O(1), тогда как операции удаления и извлечения-мин выполняются в амортизированном O (LG N) время. Если вы хотите получить хорошую справку по этому вопросу, я настоятельно рекомендую взять копию "Введение в алгоритмы, 2-е издание" CLRS и прочитать главу об этом. Это удивительно хорошо написано и очень показательно. Оригинальная статья Фредмана и Тарьяна о кучах Фибоначчи доступна в Интернете, и вы можете проверить ее. Он плотный, но хорошо обрабатывает материал.
Если вы хотите увидеть реализацию куч Фибоначчи и алгоритма Прима, я должен дать бесстыдный плагин для моих собственных реализаций:
Комментарии в обеих этих реализациях должны дать довольно хорошее описание того, как они работают; дайте мне знать, если я могу что-то сделать, чтобы уточнить!
Алгоритм Прима выбирает ребро с наименьшим весом между группой выбранных вихрей и остальными вихрями.
Поэтому для реализации алгоритма Прима вам понадобится минимальная куча. Каждый раз, когда вы выбираете ребро, вы добавляете новый вихрь в группу выбранных вами вихрей, и все смежные ребра попадают в кучу.
Затем вы снова выбираете ребро с минимальным значением из кучи.
Итак, времена, которые мы получаем:
Фибоначчи:
Выбор минимального ребра = O (время удаления минимума) = O (log (E)) = O (log (V))
Вставка ребер в кучу = O (время вставки элемента в кучу) = 1
Мин куча:
Выбор минимального ребра = O (время удаления минимума из кучи) = O (log (E)) = O (log (V))
Вставка ребер в кучу = O (время вставки элемента в кучу) = O (log (E)) = O (log (V))
(Помните, что E =~ V^2 ... так что log(E) == log(V^2) == 2Log(V) = O(log(V))
Итак, всего у вас есть E вставок и V минимальных выборов (в конце концов, это дерево).
Таким образом, в Мин куче вы получите:
O (Vlog (V) + Elog (V)) == O (Elog (V))
А в куче Фибоначчи вы получите:
O (Vlog (V) + E)
Я реализовал Dijkstra с использованием куч Фибоначчи несколько лет назад, и проблема довольно похожа. По сути, преимущество кучи Фибоначчи состоит в том, что она делает нахождение минимума множества постоянной операцией; так что это очень подходит для Prim и Dijkstra, где на каждом шаге вы должны выполнить эту операцию.
Почему это хорошо
Сложность этих алгоритмов, использующих биномиальную кучу (которая является более "стандартным" способом), составляет O(E * log V), потому что - примерно - вы будете пробовать каждое ребро (E), и для каждого из них вы будете либо добавлять новая вершина к вашей биномиальной куче (log V) или уменьшите ее ключ (log V), а затем должны найти минимум вашей кучи (еще один log V).
Вместо этого, когда вы используете кучу Фибоначчи, стоимость вставки вершины или уменьшения ее ключа в куче постоянна, поэтому у вас есть только O(E) для этого. НО удаление вершины - это O(log V), так как в конце будет удалена каждая вершина, которая добавляет O(V * log V) для общего O(E + V * log V).
Поэтому, если ваш график достаточно плотный (например, E >> V), использование кучи Фибоначчи лучше, чем биномиальной кучи.
Как
Таким образом, идея состоит в том, чтобы использовать кучу Фибоначчи для хранения всех вершин, доступных из поддерева, которое вы уже построили, с индексом веса наименьшего ребра, ведущего к нему. Если вы поняли реализацию или алгоритм Прима с использованием другой структуры данных, то вместо использования кучи Фибоначчи нет особых трудностей - просто используйте методы кучи Фибоначчи и deletemin, как вы это обычно делаете, и используйте метод lowerkey для обновления вершины. когда вы отпускаете край, ведущий к нему.
Единственная сложная часть заключается в реализации фактической кучи Фибоначчи.
Я не могу дать вам все детали реализации здесь (это заняло бы страницы), но когда я сделал это, я сильно полагался на Введение в алгоритмы (Cormen et al). Если у вас его еще нет, но вас интересуют алгоритмы, я настоятельно рекомендую вам получить его копию! Он не зависит от языка и предоставляет подробные объяснения обо всех алгоритмах стандартов, а также их доказательства, и, безусловно, расширит ваши знания и способность использовать все из них, а также разрабатывать и доказывать новые. Этот PDF-файл (со страницы Википедии, на который вы ссылаетесь) содержит некоторые детали реализации, но он определенно не так понятен, как " Введение в алгоритмы".
У меня есть отчет и презентация, которую я написал после этого, которая объясняет немного, как действовать (для Дейкстры - см. Конец ppt для функций кучи Фибоначчи в псевдокоде), но все это на французском языке... и мой код написан на Caml (и на французском), поэтому я не уверен, поможет ли это!!! И если вы можете что-то понять, пожалуйста, будьте снисходительны, я только начинал программировать, поэтому мои навыки кодирования были довольно плохими в то время...