Кто-нибудь на самом деле эффективно реализовал Фибоначчи-кучу?

151

Кто-нибудь из вас когда-либо реализовывал кучу Фибоначчи ? Я сделал это несколько лет назад, но это было на несколько порядков медленнее, чем использование BinHeaps на основе массива.

В то время я считал это ценным уроком того, что исследования не всегда так хороши, как утверждают. Тем не менее, многие исследовательские работы утверждают, что время работы их алгоритмов основано на использовании Fibonacci-Heap.

Вам когда-нибудь удавалось создать эффективную реализацию? Или вы работали с такими большими наборами данных, что куча Фибоначчи была более эффективной? Если так, некоторые детали будут оценены.

MDM
источник
25
Разве вы не узнали, что эти алгоритмы парни всегда прячут свои огромные константы за своими большими, большими ах ?! :) На практике, в большинстве случаев, «n» никогда не приближается даже к «n0»!
Мехрдад Афшари
Теперь я знаю. Я реализовал это, когда впервые получил свой экземпляр «Введение в алгоритмы». Кроме того, я не выбрал Тарьяна для того, кто придумал бы бесполезную структуру данных, потому что его Splay-Trees на самом деле довольно крутые.
МДМ
mdm: Конечно, это не бесполезно, но, подобно сортировке вставкой, которая превосходит быструю сортировку в небольших наборах данных, двоичные кучи могут работать лучше из-за меньших констант.
Мехрдад Афшари
1
На самом деле программа, для которой мне нужна была куча, находила Steiner-Trees для маршрутизации в VLSI-чипах, поэтому наборы данных были не совсем маленькими. Но в настоящее время (за исключением простых вещей, таких как сортировка), я всегда буду использовать более простой алгоритм, пока он не «сломается» в наборе данных.
МДМ
1
Мой ответ на это на самом деле "да". (Ну, мой соавтор на бумаге сделал.) У меня нет кода прямо сейчас, поэтому я получу больше информации, прежде чем я на самом деле отвечу. Однако, глядя на наши графики, я замечаю, что кучи F сравнивают меньше, чем кучи b. Вы использовали что-то, где сравнение было дешево?
А. Рекс

Ответы:

136

Библиотеки Boost C ++ включают в себя реализацию куч Фибоначчи boost/pending/fibonacci_heap.hpp. Этот файл, очевидно, был в pending/течение многих лет, и по моим прогнозам никогда не будет принят. Кроме того, в этой реализации были ошибки, которые исправил мой знакомый и крутой парень Аарон Виндзор. К сожалению, в большинстве версий этого файла, которые я смог найти в Интернете (и в версии Ubuntu libboost-dev), все еще были ошибки; Мне пришлось вытащить чистую версию из хранилища Subversion.

Начиная с версии 1.49 библиотеки Boost C ++ добавили много новых структур кучи, включая кучу Фибоначчи.

Мне удалось скомпилировать dijkstra_heap_performance.cpp с измененной версией dijkstra_shortest_paths.hpp, чтобы сравнить кучи Фибоначчи и двоичные кучи. (В строке typedef relaxed_heap<Vertex, IndirectCmp, IndexMap> MutableQueueизмените relaxedна fibonacci.) Сначала я забыл скомпилировать с оптимизациями, и в этом случае Фибоначчи и двоичные кучи работают примерно одинаково, причем кучи Фибоначчи обычно опережают на незначительную величину. После того, как я скомпилировал с очень сильными оптимизациями, двоичные кучи получили огромный импульс. В моих тестах кучи Фибоначчи превосходили только двоичные кучи, когда граф был невероятно большим и плотным, например:

Generating graph...10000 vertices, 20000000 edges.
Running Dijkstra's with binary heap...1.46 seconds.
Running Dijkstra's with Fibonacci heap...1.31 seconds.
Speedup = 1.1145.

Насколько я понимаю, это касается фундаментальных различий между кучами Фибоначчи и двоичными кучами. Единственное реальное теоретическое различие между этими двумя структурами данных заключается в том, что кучи Фибоначчи поддерживают ключ уменьшения (в амортизированном виде) в постоянное время. С другой стороны, двоичные кучи получают большую производительность от своей реализации в виде массива; использование явной структуры указателя означает, что кучи Фибоначчи сильно страдают от производительности.

Таким образом, чтобы на практике использовать кучи Фибоначчи , вы должны использовать их в приложении, в котором невероятно часто используются кнопки В терминах Дейкстры это означает, что основной граф является плотным. Некоторые приложения могут быть внутренне уменьшены_ключом; Я хотел попробовать алгоритм минимального разреза Нагомочи-Ибараки, потому что, очевидно, он генерирует много ключей lower_keys , но это было слишком много усилий, чтобы заставить работать сравнение по времени.

Предупреждение : возможно, я сделал что-то не так. Вы можете попытаться воспроизвести эти результаты самостоятельно.

Теоретическое примечание . Улучшенная производительность кучи Фибоначчи при уменьшении ключа важна для теоретических приложений, таких как время выполнения Дейкстры. Кучи Фибоначчи также превосходят двоичные кучи при вставке и слиянии (обе амортизируются постоянным временем для кучи Фибоначчи). Вставка, по сути, не имеет значения, потому что она не влияет на время выполнения Dijkstra, и довольно легко изменить двоичные кучи, чтобы также иметь вставку в амортизированном постоянном времени. Слияние в постоянное время является фантастическим, но не имеет отношения к этому приложению.

Личное примечание : мой друг и я однажды написали статью, объясняющую новую очередь приоритетов, в которой была предпринята попытка воспроизвести (теоретическое) время работы куч Фибоначчи без их сложности. Документ так и не был опубликован, но мой соавтор реализовал двоичные кучи, кучи Фибоначчи и нашу собственную очередь приоритетов для сравнения структур данных. Графики экспериментальных результатов показывают, что кучи Фибоначчи немного превосходят двоичные кучи с точки зрения общего сравнения, что позволяет предположить, что кучи Фибоначчи будут работать лучше в ситуации, когда стоимость сравнения превышает накладные расходы. К сожалению, у меня нет доступного кода, и, по-видимому, в вашей ситуации сравнение дешево, поэтому эти комментарии актуальны, но не имеют прямого отношения.

Кстати, я настоятельно рекомендую попытаться сопоставить время выполнения кучи Фибоначчи с вашей собственной структурой данных. Я обнаружил, что я просто заново изобрел кучу Фибоначчи. Раньше я думал, что все сложности кучи Фибоначчи были случайными идеями, но потом я понял, что все они были естественными и довольно вынужденными.

А. Рекс
источник
Спасибо! Этот вопрос долго сидел у меня в голове. Я на самом деле реализовал использование Дейкстры с помощью Fibonacci-Heaps, прежде чем попытался использовать Steiner-Trees. Однако, похоже, что мои графики куда менее плотны, чем в вашем примере. У них были миллионы узлов, но средняя степень всего 5-6.
MDM
Производительность Fib Heap предсказуема с помощью последовательности операций. Я написал алгоритм с большой кучей, который быстрее заканчивался с кучей Fib (против Bin Heap). Уловка состояла в том, чтобы скомпоновать работу. Независимо от частоты какой-либо операции, разница заключается в следующем: DecreaseKey - ExtractMin - DecreaseKey - ExtractMin против DecreaseKey - DecreaseKey - ExtractMin - ExtractMin (продолжение ниже)
Gaminic
Последний будет примерно в два раза быстрее, потому что 2nd ExtractMin почти бесплатен. Наш алгоритм извлекает партию элементов Min, из которых многие отбрасываются; пустая трата на кучу бен, но лучше на кучу фиб. К сожалению, это не ясно отражено в сложности времени, которую люди предоставляют, говоря об алгоритмах на основе кучи. С Амортизированными границами общая сложность не просто # операции * сложность операции.
Gaminic
1
Есть ли шанс попробовать связать кучу и / или расслабленную кучу?
Томас Ахле
1
Я не уверен, почему ваши результаты оказались такими близкими, я использовал STL priority_queue против собственной реализации кучи Фибоначчи, и бинарная куча отставала с большим отрывом в моих тестах .
Николас Пипитоне
33

Кнут провел сравнение между кучей Фибоначчи и двоичными кучами для минимальных остовных деревьев еще в 1993 году для своей книги Stanford Graphbase . Он обнаружил, что фибоначчи на 30–60% ниже, чем двоичные кучи при размерах тестируемого им графа, 128 вершин с различной плотностью.

Исходный код находится в C (или , скорее , CWEB который представляет собой нечто среднее между C, математике и текс) в разделе MILES_SPAN.

paperhorse
источник
1

отказ

Я знаю, что результаты довольно схожи и «похоже, что во время выполнения полностью доминирует нечто иное, чем куча» (@Alpedar). Но я не смог найти никаких доказательств этого в коде. Код открыт, поэтому, если вы можете найти что-то, что может повлиять на результат теста, пожалуйста, сообщите мне.


Возможно, я сделал что-то не так, но я написал тест , основанный на сравнении A.Rex и anwser:

  • Фибоначчи-Heap
  • D-Ary-heap (4)
  • Binary-Heap
  • Relaxed-Heap

Время выполнения (только для полных графиков) для всех куч было очень близко. Тест был выполнен для полных графов с 1000, 2000, 3000, 4000, 5000, 6000, 7000 и 8000 вершин. Для каждого теста было сгенерировано 50 случайных графиков, а на выходе - среднее время каждой кучи:

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


Вот результаты (в секундах):

таблица результатов кучи

Гильерме Торрес Кастро
источник
4
Сколько граней в каждом случае? И какой алгоритм вы используете именно? Ваши результаты не имеют смысла, если мы не знаем, с чем имеем дело.
kokx
К сожалению, все графы завершены, так что вы можете рассчитать количество ребер для каждого случая. Что вы имеете в виду, «ты бежишь точно». Они находятся во главе столов.
Гильерме Торрес Кастро
22
Это выглядит так, как будто во время выполнения полностью доминирует нечто иное, чем куча (это может быть генерация графика или некоторый ввод-вывод). Эти почти точно такие же результаты невероятны.
Альпедар
2
Ну, может быть, во времени доминирует что-то еще, но я уверен, что это не IO или генерация графиков. В любом случае, исходный код доступен, и я буду очень рад, если кто-нибудь найдет ошибку и исправит меру.
Гильерме Торрес Кастро
Эти тесты, кажется, измеряют что-то совершенно другое. Не могли бы вы прокомментировать тест, который вы провели? Помните, что задача кратчайшего пути на полном графе равна O (1), если расстояния геометрические / евклидовы.
Gaminic
0

Я также провел небольшой эксперимент с кучей Фибоначчи. Вот ссылка для деталей: Эксперимент-с-Дайкстра-алгоритм . Я просто погуглил термины «куча java Фибоначчи» и попробовал несколько существующих реализаций кучи Фибоначчи с открытым исходным кодом. Кажется, у некоторых из них есть проблемы с производительностью, но есть и такие, которые весьма хороши. По крайней мере, в моем тесте они бьют производительность наивного и двоичного PQ кучи. Может быть, они могут помочь реализовать эффективный.

gabormakrai
источник