Algorytm Tarjana znajdowania najniższego wspólnego przodka

Algorytm offline Tarjana do znajdowania najniższego wspólnego przodka

Algorytm offline Tarjana to metoda obliczania najniższego wspólnego przodka dla pary węzłów w drzewie, oparta na strukturze zbiorów rozłącznych.

Najniższym wspólnym przodkiem dwóch wierzchołków d oraz e w ukorzenionym drzewie T jest taki węzeł, który jest najbliższym wspólnym przodkiem d i e, mającym najwyższy poziom w drzewie T. Algorytm ten został opracowany przez Roberta Tarjana w 1979 roku. Należy on do klasy algorytmów offline, co oznacza, że przed jego uruchomieniem należy dostarczyć wszystkie pary wierzchołków, dla których będzie obliczany najniższy wspólny przodek.

Najprostsza wersja algorytmu wykorzystuje strukturę „find union”, jednak w przeciwieństwie do innych algorytmów wyszukiwania wspólnego przodka, może nie zapewniać stałego czasu działania dla każdej operacji, gdy liczba par wierzchołków jest zbliżona do liczby węzłów w drzewie. Ostatnie udoskonalenia przyspieszają działanie algorytmu do czasów liniowych.

Pseudokod

Poniższy pseudokod oblicza najniższego wspólnego przodka dla każdej pary z zestawu P. Korzeń drzewa jest przechowywany w zmiennej r, natomiast dzieci węzła n znajdują się w zbiorze n.children. W przypadku tego algorytmu offline zbiór P musi być zdefiniowany przed rozpoczęciem działania algorytmu. W procedurze wykorzystywane są funkcje MakeSet, Find oraz Union ze zbiorów rozłącznych. MakeSet(u) tworzy singleton z u, Find(u) zwraca reprezentanta zbioru, do którego należy u, a Union(u, v) łączy zbiory, które zawierają węzły u oraz v.

Funkcja TarjanOLCA(r) jest na początku wywoływana z parametrem równym korzeniowi r.

funkcja TarjanOLCA(u)

MakeSet(u)

u.ancestor := u

dla każdego v należącego do u.children wykonaj

TarjanOLCA(v)

Union(u,v)

Find(u).ancestor := u

u.color := black;

dla każdego v takiego, że {u,v} należy do P wykonaj

if v.colour == black

zwróć wynik: Find(v).ancestor

Po początkowej inicjalizacji każdy węzeł ma kolor biały, a na czarno zostaje pokolorowany w momencie, gdy wszystkie jego dzieci zostaną odwiedzone. Najniższy wspólny przodek pary {u,v} może być wyznaczony przez wywołanie funkcji Find(v).ancestor w momencie, gdy węzeł u jest pokolorowany na czarno, a v jest już czarny. W przeciwnym razie, wynik będzie dostępny później jako Find(u).ancestor, gdy v również zostanie pokolorowane na czarno.

Poniżej przedstawiono zoptymalizowaną wersję funkcji MakeSet, Find oraz Union działających na zbiorach rozłącznych.

funkcja MakeSet(x)

x.parent := x

x.rank := 0

funkcja Union(x, y)

xRoot := Find(x)

yRoot := Find(y)

if xRoot.rank > yRoot.rank

yRoot.parent := xRoot

else if xRoot.rank < yRoot.rank

xRoot.parent := yRoot

else if xRoot != yRoot

yRoot.parent := xRoot

xRoot.rank := xRoot.rank + 1

funkcja Find(x)

if x.parent == x

return x

else

x.parent := Find(x.parent)

return x.parent

Przypisy

Bibliografia

H. N. Gabow, R. E. Tarjan. A linear-time algorithm for a special case of disjoint set union. „Proceedings of the 15th ACM Symposium on Theory of Computing (STOC)”, s. 246–251, 1983. DOI: 10.1145/800061.808753.

Tarjan. Applications of path compression on balanced trees. „Journal of the ACM”. 4 (26), s. 690–715, 1979. DOI: 10.1145/322154.322161.

Przeczytaj u przyjaciół: