Wykład 6 Drzewa poszukiwań binarnych (BST) 1
O czym będziemy mówić Definicja Operacje na drzewach BST: Search Minimum, Maximum Predecessor, Successor Insert, Delete Struktura losowo budowanych drzew BST 2
Wprowadzenie Poszukujemy dynamicznego ADT, który efektywnie będzie obsługiwał następujące operacje: Wyszukiwanie elementu (Search) Znajdowanie Minimum/Maximum Znajdowanie poprzednika/następnika (Predecessor/Successor) Wstawianie/usuwanie elementu (Insert/Delete) Wykorzystamy drzewo binarne! Wszystkie operacje powinny zajmować czas Θ(lg n) Drzewo powinno być zawsze zbalansowane inaczej czas będzie proporcjonalny do wysokości drzewa (gorszy od O(lg n))! 3
Drzewo poszukiwań binarnych (binary search tree) Struktura drzewa z korzeniem Każdy węzeł x posiada pola left(x), right(x), parent(x), oraz key(x). Własność drzewa BST: Niech x będzie dowolnym węzłem drzewa, natomiast niech y będzie należał do poddrzewa o korzeniu w x wtedy:. Jeżeli należy do lewego poddrzewa to: key(y) key(x) Jeżeli należy do prawego poddrzewa to : key(y) > key(x) 4
Przykład BST 5 2 3 7 3 2 5 8 7 5 8 5 Metody przechodzenia przez drzewo : In-order, pre-order, post-order 5
Poszukiwanie w drzewie BST Tree-Search(x,k) if x = null or k = key[x] then return x if k < key[x] then return Tree-Search(left[x],k) else return Tree-Search(right[x],k) rekurencyjnie Tree-Search(x,k) while x null and k key[x] do if k < key[x] then x left[x] else x right[x] return x iteracyjnie złożoność: O(h) 6
Przykład Poszukiwany klucz: 13 7
Przechodzenie przez wszystkie węzły drzewa Inorder-Tree-Walk(x) if x null then Inorder-Tree-Walk(left[x]) print key[x] Inorder-Tree-Walk(right[x]) czas wykonania: T(0) = Θ(1) T(n)=T(k) + T(n k 1) + Θ(1) złożoność: Θ(n) 8
Odnajdowanie minimum i maksimum Tree-Minimum(x) while left[x] null do x left[x] return x Tree-Maximum(x) while right[x] null do x right[x] return x złożoność: O(h) 9
Przykład minimum 10
Odnajdowanie następnika Następnikiem x nazywamy najmniejszy element y wśród elementów większych od x Następnik może zostać odnaleziony bez porównywania kluczy. Jest to : 1. null jeśli x jest największym z węzłów. 2. minimum w prawym poddrzewie t jeśli ono istnieje. 3. najmniejszy z przodków x, dla których lewy potomek jest przodkiem x. 11
Odnajdowanie następnika x z y minimum w prawym poddrzewie t x najmniejszy z przodków x, dla których lewy potomek jest przodkiem x 12
Odnajdowanie następnika Tree-Successor(x) if right[x] null // przypadek 2 then return Tree-Minimum(right[x]) y parent[x] while y null and x = right[y] // przypadek 3 do x y y parent[y] return y 13
Przykład Poszukajmy następników dla 15 (przyp. 2), 13 (przyp. 3) 14
Wstawianie elementów Wstawianie jest bardzo zbliżone do odnajdowania elementu: Odnajdujemy właściwe miejsce w drzewie, w które chcemy wstawić nowy węzeł z. Dodawany węzeł z zawsze staje się liściem. Zakładamy, że początkowo left(z) oraz right(z) mają wartość null. 15
Wstawanie przykład Wstawiamy 13 do drzewa 12 5 18 2 9 15 19 z 13 17 16
Wstawianie pseudokod Tree-Insert(T,z) y null x root[t] while x null do y x if key[z] < key[x] then x left[x] else x right[x] parent[z] y // dla pustego drzewa if y = null then root[t] z else if key[z] < key[y] then left[y] z else right[y] z 17
Usuwanie z drzewa BST Usuwanie elementu jest bardziej skomplikowane niż wstawianie. Można rozważać trzy przypadki usuwania węzła z: 1. z nie ma potomków 2. z ma jednego potomka 3. z ma 2 potomków przypadek 1: usuwamy z i zmieniamy u rodzica wskazanie na null. przypadek 2: usuwamy z a jego dziecko staje się dzieckiem rodzica. przypadek 3:najbardziej złożony; nie można po prostu usunąć węzła i przenieść dzieci do rodzica drzewo przestałoby być binarne! 18
Usuwanie z drzewa BST - przypadek 1 usuwamy delete 19
Usuwanie z drzewa BST przypadek 2 Usuwany węzeł 20
Usuwanie z drzewa BST przypadek 3 Rozwiązanie polega na zastąpieniu węzła jego następnikiem. założenie: jeśli węzeł ma dwóch potomków, jego następnik ma co najwyżej jednego potomka. dowód: jeśli węzeł ma 2 potomków to jego następnikiem jest minimum z prawego poddrzewa. Minimum nie może posiadać lewego potomka (inaczej nie byłoby to minimum) 21
Usuwanie z drzewa BST przypadek 3 Usuwamy z z δ y δ α β α β y w w 22
Usuwanie z drzewa BST przypadek 3 usuwamy następnik 23
Usuwanie z drzewa BST pseudokod Tree-Delete(T,z) if left[z] = null or right[z] = null /* p. 1 lub 2 then y z else y Tree-Successor(z) if left[y] null then x left[y] else x right[y] if x null then parent[x] parent[y] if parent[y] = null then root[t] x else if y = left[parent[y]] then left[parent[y]] x else right[parent[y]] x if y z then key[z] key[y] return y 24
Analiza złożoności Usuwanie: dwa pierwsze przypadki wymagają O(1) operacji: tylko zamiana wskaźników. Przypadek 3 wymaga wywołania Tree-Successor, i dlatego wymaga czasu O(h). Stad wszystkie dynamiczne operacje na drzewie BST zajmują czas O(h), gdzie h jest wysokością drzewa. W najgorszym przypadku wysokość ta wynosi O(n) 25