Disjunktní množinový systém

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 22. června 2017; kontroly vyžadují 13 úprav .

Disjoint-set system ( angl.  disjoint-set , nebo union-find data structure ) je datová struktura , která umožňuje spravovat sadu prvků, rozdělenou do disjunktních podmnožin. V tomto případě je každé podmnožině přiřazen její zástupce – prvek této podmnožiny. Abstraktní datová struktura je definována sadou tří operací: .

Používá se k ukládání připojených komponent do grafů , zejména Kruskalův algoritmus potřebuje pro efektivní implementaci podobnou datovou strukturu.

Definice

Nechť konečnou množinu rozdělenou na neprotínající se podmnožiny ( třídy ) :

.

Každé podmnožině je přiřazen zástupce . Odpovídající systém disjunktních množin podporuje následující operace:

Algoritmická implementace

Triviální implementace ukládá vlastnictví prvků z a zástupců v indexovém poli . V praxi se častěji používají sady stromů . To může výrazně zkrátit čas potřebný pro operaci Najít . V tomto případě je zástupce zapsán do kořene stromu a zbývající prvky třídy jsou zapsány do uzlů pod ním.

Heuristika

K urychlení operací Union a Find lze použít heuristiku Union-By-Size , Union-By-Height , Random-Union a kompresi cest .

V heuristice Union-By-Size je během operace kořen menšího stromu zavěšen pod kořen většího stromu. Tento přístup zachovává rovnováhu stromu. Hloubka každého podstromu nemůže přesáhnout . Pomocí této heuristiky se doba operace Najít v nejhorším případě prodlouží z na . Pro efektivní implementaci se navrhuje ukládat počet uzlů ve stromu do kořene.

Heuristika Union-By-Height je podobná jako Union-By-Size , ale místo velikosti používá výšku stromu.

Heuristika Random-Union využívá skutečnosti, že je možné neutrácet další paměť pro uložení počtu uzlů ve stromu: stačí náhodně vybrat kořen - toto řešení poskytuje rychlost na náhodné dotazy, která je zcela srovnatelná s ostatními implementací. Pokud však existuje mnoho dotazů jako „sloučit velkou sadu s malou“, tato heuristika zlepšuje očekávanou hodnotu (tedy průměrnou dobu běhu) pouze o faktor dva, takže se nedoporučuje používat ji bez heuristika komprese cesty.

K urychlení operace se používá heuristika komprese cesty . Při každém novém hledání jsou všechny prvky, které jsou na cestě od kořene k požadovanému prvku, zavěšeny pod kořen stromu. V tomto případě bude operace Najít fungovat v průměru , kde  je inverzní funkce Ackermanovy funkce . To vám umožňuje výrazně urychlit práci, protože pro všechny v praxi používané hodnoty nabývá hodnoty menší než 5.

Příklad implementace

Implementace v C++:

const int MAXN = 1000 ; int p [ MAXN ], pořadí [ MAXN ]; void MakeSet ( int x ) { p [ x ] = x ; hodnost [ x ] = 0 ; } int Najít ( int x ) { return ( x == p [ x ] ? x : p [ x ] = Najít ( p [ x ]) ); } void Union ( int x , int y ) { if ( ( x = Najít ( x )) == ( y = Najít ( y )) ) vrátit se ; if ( hodnost [ x ] < hodnost [ y ] ) p [ x ] = y ; jinak { p [ y ] = x ; if ( hodnost [ x ] == hodnost [ y ] ) ++ pořadí [ x ]; } }

Implementace ve Free Pascalu:

const MAX_N = 1000 ; var Parent , Rank : array [ 1 .. MAX_N ] of LongInt ; procedura swap ( var x , y : LongInt ) ; var tmp : LongInt ; začít tmp := x ; x : = y y := tmp ; konec ; procedura MakeSet ( x : LongInt ) ; začít Nadřazený [ x ] := x ; Pořadí [ x ] := 0 ; konec ; funkce Najít ( x : LongInt ) : LongInt ; začít if ( Parent [ x ] <> x ) then Rodič [ x ] := Najít ( Rodič [ x ] ) ; Exit ( Parent [ x ] ) ; konec ; procedura Union ( x , y : LongInt ) ; začít x := Najít ( x ) ; y := Najít ( y ) ; if ( x = y ) then exit () ; if ( Pořadí [ x ] < Pořadí [ y ] ) then swap ( x , y ) ; Rodič [ y ] := x ; if ( Pořadí [ x ] = Pořadí [ y ] ) pak inc ( Pořadí [ x ] ) ; konec ;

Viz také

Literatura

Odkazy