Algorytmy i Struktury Danych, 5. ćwiczenia
2015-10-30
Spis treści
1 System różnych reprezentantów 1
2 d-kopce 2
3 Kopiec lewicowy 2
4 Zadanie drzewowe z klasówki 3
1 System różnych reprezentantów
Dana jest rodzina n niepustych podzbiorów zbioru {1, 2, . . . , n}, z których każdy to całkowitoliczbowy przedział postaci [i, j], i ≤ j. Zaprojektuj efektywny algo- rytm sprawdzania, czy zadana rodzina posiada system różnych reprezentantów, a jeśli tak, to podaje jeden z nich.
Możemy udowodnić, że następujący algorytm zachłanny rozwiązuje problem:
• dane: n przedziałów [li, ri],
• niech K oznacza kopiec zawierający przedziały uporządkowane rosnąco według prawych końców, początkowo kopiec jest pusty
• y = 1
• for i ∈ 1, . . . , n do:
– dodaj do kopca wszystkie przedziały postaci [i, rk],
– jeśli kopiec nie jest pusty, to niech [lr, rk] = ExtractM in(K) – jeśli y > rk to zakończ algorytm — BRAK ROZWIĄZANIA – w przeciwnym przypadku, przydziel jako reprezentanta [lr, rk] war-
tość max(lr, y) – y := max(lr, y) + 1
1
2 d-kopce
d–kopiec do drzewo zupełne o stopniu d z porządkiem kopcowym (min w korze- niu). Należy pokazać, że poszczególne operacje wykonuje się w czasie:
• Min — O(1)
• DeleteMin — O(d · logd(n))
• DecreaseKey — O(logd(n))
Koszt implementacji algorytmu Dijkstry, przy użyciu d–kopców: O(nd · logd(n) + m · logd(n)).
Zanalizować jak należy dobrać d w zależności od m i n (jeśli za d weźmiemy max(2, dm/ne) to dostajemy O(log m/nm log n)).
3 Kopiec lewicowy
Kopiec lewicowy to drzewo binarne, spełniające:
•
• warunek kopca: key(x) ≥ key(parent(x)),
• oraz dist(lef t(x)) ≤ dist(right(x)), gdzie dist(x) jest odległością do naj- bliższego potomka o mniej niż 2 synach (przyjmujemy, że dist(null) = −1).
Przydatna własność: Jeśli v jest korzeniem kopca lewicowego, to zawiera on co najmniej 2dist(a) węzłów. Czyli jeśli kopiec zawiera n węzłów, to dist(root) = O(log n).
Podstawową operacją jest złączanie dwóch kopców:
Merge(a, b)
1: if a=null then
2: return b;
3: else if b=null then
4: return a;
5: end if
6: if key(b) < key(a) then
7: swap(a, b)
8: end if
9: left(a)=merge(left(a), b)
10: if dist(right(a)) < dist(lef t(a)) then
11: swap(right(a), left(a))
12: end if
13: if lef t(a)=null then
14: dist(a)=0
15: else
16: dist(a)=1+dist(left(a))
17: end if
18: return a
Łatwo pokazać, że złożoność operacji merge wynosi O(dist(a) + dist(b)), czyli O(log n).
Operacje insert i extractM in można zaimplementować używając operacji merge.
2
Insert(r, x)
1: p=MakeTree(x)
2: r=Merge(r, p)
ExtracMin(r)
1: min=r.value
2: r=Merge(r.lef t, r.right)
3: return min
Operacje IncreaseKey/DecreaseKey możemy zaimplementować w następujący sposób (T – kopiec lewicowy, v – zmieniany węzeł, x – nowa wartość węzła x):
• usuwamy wskazany węzeł v z kopca T (musimy zadbać by wszystkie wa- runki kopca lewicowego były nadal zachowane)
• tworzymy jednoelementowy kopiec lewicowy T0 z wartością x,
• scalamy T i T0.
Usuwanie węzła z kopca możemy wykonać w następujący sposób:
RemoveNode(v)
1: zastąp v przez Merge(v.lef t, v.right)
2: p=v.parent
3: while p 6= nil do
4: if dist(p.lef t) > dist(p.right) then
5: swap(p.lef t, p.right)
6: end if
7: if dist(p) = dist(p.lef t) + 1 then
8: break
9: else
10: dist(p) = dist(p.lef t) + 1; p = p.parent
11: end if
12: end while
Analiza pojedynczego kroku pętli while:
• v należy do poddrzewa p.right:
– jeśli wykonano operację swap, to kopiec musi mieć co najmniej 2k węzłów (gdzie k to odległość pomiędzy v i p)
– wpp. algorytm kończy działanie,
• v należy do poddrzewa p.lef t, jednak zauważmy, że liczba kroków tego typu nie może przekroczyć O(log n)
4 Zadanie drzewowe z klasówki
Dane jest n-węzłowe drzewo binarne z różnymi kluczami w węzłach. Rozważamy następujący algorytm rekurencyjny przywracania porządku kopcowego w takim drzewie:
Jeśli drzewo składa się z co najwyżej jednego węzła, to porządek kopcowy jest przywrócony. W przeciwnym przypadku znajdujemy w drzewie węzeł z najmniejszym kluczem i zamieniamy klucze z korzenia i ze znalezionego węzła, a następnie rekurencyjnie przywracamy porządek kopcowy w lewym i prawym poddrzewie korzenia.
3
1. (4 punkty) Przyjmijmy, że węzeł z najmniejszym kluczem znajdujemy jedną z metod obchodzenia drzewa (preorder, inorder lub postorder).
• (1 punkt) Jaka jest (asymptotycznie) pesymistyczna złożoność przy- wracania porządku kopcowego wyrażona jako funkcja n?
• (3 punkty) Jaka jest złożoność powyższego algorytmu dla drzewa o wysokości blog nc?
2. (8 punktów) Zaproponuj strukturę danych, które umożliwi efektywne wy- konywanie następujących operacji na n-węzłowym drzewie binarnym:
M in(v):: znajdź w poddrzewie o korzeniu v węzeł z najmniejszym klu- czem;
Exch(u, v):: zamień klucze z węzłów u i v.
4