Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Дискр.Мат-ка. Алгоритмы поиска на графах.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
55.78 Кб
Скачать

Доказательство корректности

Пусть l(v) — длина кратчайшего пути из вершины a в вершину v. Докажем по индукции, что в момент посещения любой вершины z, d(z)=l(z). База. Первой посещается вершина a. В этот момент d(a)=l(a)=0. Шаг. Пускай мы выбрали для посещения вершину . Докажем, что в этот момент d(z)=l(z). Для начала отметим, что для любой вершины v, всегда выполняется  (алгоритм не может найти путь короче, чем кратчайший из всех существующих). Пусть P — кратчайший путь из a в z, y — первая непосещённая вершина на P, x — предшествующая ей (следовательно, посещённая). Поскольку путь P кратчайший, его часть, ведущая из a через x в y, тоже кратчайшая, следовательно l(y)=l(x)+w(xy). По предположению индукции, в момент посещения вершины x выполнялось d(x)=l(x), следовательно, вершина y тогда получила метку не больше чем d(x)+w(xy)=l(x)+w(xy)=l(y) (если существует k, такое что l(k) + w(ky) < l(x) + w(xy) то x не принадлежит P). Следовательно, d(y)=l(y). С другой стороны, поскольку сейчас мы выбрали вершину z, её метка минимальна среди непосещённых, то есть . Комбинируя это с , имеем d(z)=l(z), что и требовалось доказать.

Поскольку алгоритм заканчивает работу, когда все вершины посещены, в этот момент d=l для всех вершин.

Сложность алгоритма

Сложность алгоритма Дейкстры зависит от способа нахождения вершины v, а также способа хранения множества непосещенных вершин и способа обновления меток. Обозначим через n количество вершин, а черезm — количество ребер в графе G.

  • В простейшем случае, когда для поиска вершины с минимальным d[v] просматривается все множество вершин, а для хранения величин d — массив, время работы алгоритма есть O(n2 + m). Основной цикл выполняется порядка n раз, в каждом из них на нахождение минимума тратится порядка n операций, плюс количество релаксаций (смен меток), которое не превосходит количества ребер в исходном графе.

  • Для разреженных графов (то есть таких, для которых m много меньше n²) непосещенные вершины можно хранить в двоичной куче, а в качестве ключа использовать значения d[i], тогда время извлечения вершины из  станет log n, при том, что время модификации d[i] возрастет до logn. Так как цикл выполняется порядка n раз, а количество релаксаций не больше m, скорость работы такой реализацииO(nlog n + mlog n)

  • Если для хранения непосещенных вершин использовать фибоначчиеву кучу, для которой удаление происходит в среднем за O(log n), а уменьшение значения в среднем за O(1), то время работы алгоритма составит O(nlog n + m). Однако, согласно сайту intuit.ru,[3]

скрытые константы в асимптотических оценках трудоемкости велики и использование фибоначчиевых куч редко оказывается целесообразным: обычные двоичные (d-ичные) кучи на практике эффективнее.

Альтернативами им служат толстые кучи, тонкие кучи и кучи Бродала, обладающие теми же асимптотическими оценками, но меньшими константами.[4]

Фибоначчиева куча

 этого термина существуют и другие значения, см. Куча (значения).

Фибоначчиева куча (англ. Fibonacci heap) — структура данных, представляющая собой набор деревьев, упорядоченных в соответствии со свойством неубывающей пирамиды. Фибоначчиевы кучи были введены Майклом Фредманом и Робертом Тарьяном в 1984 году.

Структура является реализацией абстрактного типа данных «Очередь с приоритетом», и замечательна тем, что операции, в которых не требуется удаление, имеют амортизированное время работы, равное O(1) (для двоичной кучи ибиномиальной кучи амортизационное время работы равно O(log n)). Кроме стандартных операций INSERT, MIN, EXTRACT-MIN фибоначчиева куча позволяет за время O(1) выполнять операцию UNION слияния двух куч.

Структура

  • Фибоначчиева куча H представляет собой набор деревьев.

  • Каждое дерево в H подчиняется свойству неубывающей пирамиды (англ. min-heap property): ключ узла не меньше ключа его родительского узла.

  • Каждый узел x в H содержит следующие указатели и поля:

    • key[x] — поле, в котором хранится ключ;

    • p[x] — указатель на родительский узел;

    • child[x] — указатель на один из дочерних узлов;

    • left[x] — указатель на левый сестринский узел;

    • right[x] — указатель на правый сестринский узел;

    • degree[x] — поле, в котором хранится количество дочерних узлов;

    • mark[x] — логическое значение, которое указывает, были ли потери узлом xдочерних узлов, начиная с момента, когда x стал дочерним узлом какого-то другого узла.

  • Дочерние узлы x объединены при помощи указателей left и right в один циклический дважды связанный список дочерних узлов (англ. child listx.

  • Корни всех деревьев в H связаны при помощи указателей left и right в циклический дважды связанный список корней (англ. root list).

  • Обращение к H выполняется посредством указателя min[H] на корень дерева с минимальным ключом. Этот узел называется минимальным узлом (англ. minimum nodeH.

  • Текущее количество узлов в H хранится в n[H].

Операции

Создание новой фибоначчиевой кучи

Процедура Make_Fib_Heap возвращает объект фибоначчиевой кучи Hn[H] = 0 иmin[H] = NULL. Деревьев в H нет.

Амортизированная стоимость процедуры равна её фактической стоимости O(1).

Вставка узла

Fib_Heap_Insert(H,x)

1 degree[x] ← 0

2 p[x] ← NULL

3 child[x] ← NULL

4 left[x] ← x

5 right[x] ← x

6 mark[x] ← FALSE

7 Присоединение списка корней, содержащего x, к списку корней H

8 if min[H] = NULL или key[x] < key[min[H]]

9 then min[H] ← x

10 n[H] ← n[H] + 1

Амортизированная стоимость процедуры равна её фактической стоимости O(1).

Поиск минимального узла

Процедура Fib_Heap_Minimum возвращает указатель min[H].

Амортизированная стоимость процедуры равна её фактической стоимости O(1).

Объединение двух фибоначчиевых куч

Fib_Heap_Union(H1,H2)

1 H ← Make_Fib_Heap()

2 min[H] ← min[H1]

3 Добавление списка корней H2 к списку корней H

4 if (min[H1] = NULL) или (min[H2] ≠ NULL и key[min[H2]] < key[min[H1]])

5 then min[H] ← min[H2]

6 n[H] ← n[H1] + n[H2]

7 Освобождение объектов H1 и H2

8 return H

Амортизированная стоимость процедуры равна её фактической стоимости O(1).

Извлечение минимального узла

Fib_Heap_Extract_Min(H)

1 zmin[H]

2 if z ≠ NULL

3 then for для каждого дочернего по отношению к z узла x

4 do Добавить x в список корней H

5 p[x] ← NULL

6 Удалить z из списка корней H

7 if z = right[z]

8 then min[H] ← NULL

9 else min[H] ← right[z]

10 Consolidate(H)

11 n[H] ← n[H] − 1

12 return z

На одном из этапов операции извлечения минимального узла выполняется уплотнение (англ. consolidating) списка корней H. Для этого используется вспомогательная процедура Consolidate. Эта процедура использует вспомогательный массив A[0..D[n[H]]]. Если A[i] = y, то y в настоящий момент является корнем со степенью degree[y] = i.

Consolidate(H)

1 for i ← 0 to D(n[H])

2 do A[i] ← NULL

3 for для каждого узла w в списке корней H

4 do xw

5 ddegree[x]

6 while A[d] ≠ NULL

7 do yA[d] //Узел с той же степенью, что и у x

8 if key[x] > key[y]

9 then обменять xy

10 Fib_Heap_Link(H,y,x)

11 A[d] ← NULL

12 dd + 1

13 A[d] ← x

14 min[H] ← NULL

15 for i ← 0 to D(n[H])

16 do if A[i] ≠ NULL

17 then Добавить A[i] в список корней H

18 if min[H] = NULL или key[A[i]] < key[min[H]]

19 then min[H] ← A[i]

Fib_Heap_Link(H,y,x)

1 Удалить y из списка корней H

2 Сделать y дочерним узлом x, увеличить degree[x]

3 mark[y] ← FALSE

Амортизированная стоимость извлечения минимального узла равна O(lg n).