Zbiory rozczne Zbiory rozczne Struktura danych dla zbiorw

  • Slides: 15
Download presentation
Zbiory rozłączne

Zbiory rozłączne

Zbiory rozłączne � Struktura danych dla zbiorów rozłącznych (ang. disjoint sets data structures), lub

Zbiory rozłączne � Struktura danych dla zbiorów rozłącznych (ang. disjoint sets data structures), lub krótko zbiory rozłączne, to struktura danych, która dla ustalonego uniwersum przechowuje jego podział na mniejsze, rozłączne zbiory. � Struktura danych dla zbiorów rozłącznych pozwala efektywnie realizować następujące operacje: ◦ find(x) – odnalezienie reprezentanta zbioru, do którego należy x; ◦ union(x, y) – połączenie dwóch zbiorów zawierających elementy x i y w jeden zbiór. � Czasami rozważa się zbiory rozłączne z dodatkowymi operacjami: ◦ extract(x) – odłączenie elementu x ze zbioru, do którego należy; ◦ append(x) – dodanie do uniwersum nowego elementu x.

Implementacja zbiorów rozłącznych �Struktura danych dla zbiorów rozłącznych pozwala zarządzać rodziną dynamicznych (zmieniających się

Implementacja zbiorów rozłącznych �Struktura danych dla zbiorów rozłącznych pozwala zarządzać rodziną dynamicznych (zmieniających się w czasie) zbiorów rozłącznych. �Uniwersum pamiętamy w tablicy ze wskaźnikami na elementy. �Do każdego zbioru odwołujemy się przez jego reprezentanta.

Praca ze zbiorami rozłącznymi �Pracę ze zbiorami rozłącznymi rozpoczynamy po zainicjalizowaniu struktury: utworzeniu n

Praca ze zbiorami rozłącznymi �Pracę ze zbiorami rozłącznymi rozpoczynamy po zainicjalizowaniu struktury: utworzeniu n zbiorów jednoelementowych dla uniwersum rozmiaru n. �Czas inicjalizacji wynosi O(n). �Następnie wykonujemy na tej strukturze ciąg m operacji union() i find(). �Pamięć zajmowana przez strukturę powinna ograniczać się do O(n).

Implementacja listowa zbiorów rozłącznych �Prostym sposobem implementacji zbiorów rozłącznych jest zapamiętanie każdego zbioru jako

Implementacja listowa zbiorów rozłącznych �Prostym sposobem implementacji zbiorów rozłącznych jest zapamiętanie każdego zbioru jako listy. �Reprezentantem zbioru jest pierwszy element na liście. �Każdy element ma dodatkowo bezpośredni wskaźnik do reprezentanta.

Implementacja listowa zbiorów rozłącznych �Operacje na zbiorach rozłącznych: ◦ find(x) – z węzła x

Implementacja listowa zbiorów rozłącznych �Operacje na zbiorach rozłącznych: ◦ find(x) – z węzła x zaglądamy do reprezentanta i odczytujemy jego identyfikator – czas O(1) ◦ union(x, y) gdzie x i y są reprezentantami zbiorów – łączymy dwie listy i poprawiamy wskaźniki do reprezentanta w tej dołączonej – czas liniowy względem jej długości dołączonej listy O(n)

Implementacja listowa zbiorów rozłącznych �Prosta sztuczka zwana zbalansowanym łączeniem pozwala zmniejszyć koszt operacji union()

Implementacja listowa zbiorów rozłącznych �Prosta sztuczka zwana zbalansowanym łączeniem pozwala zmniejszyć koszt operacji union() w sensie zamortyzowanym: polega ona na tym, że podczas operacji union() zawsze dołączamy krótszą listę na koniec dłuższej (wymaga to przechowywania w węźle początkowym listy dodatkowego atrybutu zawierającego rozmiar zbioru oraz adres ostatniego elementu listy). �Koszt czasowy wykonania m operacji find() i union() wynosi O(m + n log n); zamortyzowany koszt wykonania pojedynczej operacji union() wynosi O(log n).

Implementacja listowa zbiorów rozłącznych �Pytanie: Ile razy poszczególny element na liście może zmienić reprezentanta?

Implementacja listowa zbiorów rozłącznych �Pytanie: Ile razy poszczególny element na liście może zmienić reprezentanta? �Odpowiedź: Co najwyżej log(n). �Uzasadnienie: Nowy zbiór, do którego będzie należał element jest co najmniej dwa razy większy.

Implementacja drzewiasta zbiorów rozłącznych �Prostym sposobem implementacji zbiorów rozłącznych jest zapamiętanie każdego zbioru jako

Implementacja drzewiasta zbiorów rozłącznych �Prostym sposobem implementacji zbiorów rozłącznych jest zapamiętanie każdego zbioru jako drzewa odwrotnie skierowanego (w węzłach trzymamy wskaźniki na rodziców). �Reprezentantem zbioru jest korzeń drzewa.

Implementacja drzewiasta zbiorów rozłącznych �Operacje na zbiorach rozłącznych: ◦ find(x) – z węzła x

Implementacja drzewiasta zbiorów rozłącznych �Operacje na zbiorach rozłącznych: ◦ find(x) – z węzła x rozpoczynamy wędrówkę do korzenia – czas O(wysokość drzewa) ◦ union(x, y) gdzie x i y są reprezentantami zbiorów – jedno drzewo podłączamy pod drugie drzewo – O(1)

Implementacja drzewiasta zbiorów rozłącznych �Sztuczka zwana zbalansowanym łączeniem pozwala zmniejszyć koszt operacji find() w

Implementacja drzewiasta zbiorów rozłącznych �Sztuczka zwana zbalansowanym łączeniem pozwala zmniejszyć koszt operacji find() w sensie najgorszego przypadku: polega ona na tym, że podczas operacji union() zawsze dołączamy niższe drzewo pod wyższe (wymaga to przechowywania w korzeniu drzewa dodatkowego atrybutu zawierającego wysokość krawędziową drzewa – rank). �Koszt czasowy wykonania m operacji find() i union() wynosi O(m log n); koszt wykonania pojedynczej operacji find() wynosi O(log n), ponieważ wysokość drzewa jest ograniczona przez logarytm z liczby węzłów w drzewie.

Implementacja drzewiasta zbiorów rozłącznych �Pytanie: Ile razy poszczególny zbiór może być dołączany do innego

Implementacja drzewiasta zbiorów rozłącznych �Pytanie: Ile razy poszczególny zbiór może być dołączany do innego zbioru? �Odpowiedź: Co najwyżej log(n). �Uzasadnienie: Nowy zbiór, do którego będą należały elementy podłączanego zbioru na co najmniej wykładniczą w stosunku do wysokości drzewa liczbę elementów.

Implementacja drzewiasta zbiorów rozłącznych �Sztuczka zwana kompresją ścieżek pozwala zmniejszyć głębokość części elementów po

Implementacja drzewiasta zbiorów rozłącznych �Sztuczka zwana kompresją ścieżek pozwala zmniejszyć głębokość części elementów po operacji find(): polega ona na tym, że podczas operacji find() zawsze dołączamy odwiedzone (leżące na ścieżce od danego węzła do korzenia) węzły do korzenia drzewa. �Koszt czasowy wykonania m operacji find() i union() wynosi O(m log* n); koszt wykonania pojedynczej operacji find() wynosi w najgorszym przypadku O(log n).

Zadanie 1 �Zdefiniuj drzewiastą strukturę dla zbiorów rozłącznych. �Przetestuj swoją strukturę dla losowego ciągu

Zadanie 1 �Zdefiniuj drzewiastą strukturę dla zbiorów rozłącznych. �Przetestuj swoją strukturę dla losowego ciągu operacji union() i find().

Zadanie 2 �Zdefiniuj drzewiastą strukturę dla zbiorów rozłącznych. �Zaimplementuj w swojej strukturze zbalansowane łączenie

Zadanie 2 �Zdefiniuj drzewiastą strukturę dla zbiorów rozłącznych. �Zaimplementuj w swojej strukturze zbalansowane łączenie przy union() i kompresję ścieżek przy find(). �Przetestuj swoją strukturę dla losowego ciągu operacji union() i find().