Wykład 2 Drzewa poszukiwań binarnych (BST)
Transkrypt
Wykład 2 Drzewa poszukiwań binarnych (BST)
Wykład 2 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 2 7 5 3 7 8 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) 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 rekurencyjnie 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]) 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. 2. 3. null jeśli x jest największym z węzłów. minimum w prawym poddrzewie t jeśli ono istnieje. 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 z 15 13 19 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 delete usuwamy 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 Rotacje Zachowują własność drzewa BST. Zajmują stały czas O(1) – stała ilość operacji na wskaźnikach. Rotacje w lewo i w prawo są symetryczne. 26 Rotacje Rotacja w prawo y x Rotacja w lewo x α δ β α≤x≤β i x≤y≤δ y α β δ α≤x≤y i β≤y≤δ 27 Left-Rotate Inicjuj y Left-Rotate(T,x) y right[x] right[x] left[y] Zamień lewe poddrzewo y na prawe poddrzewo x parent[left[y]] x parent[y] parent[x] Przyłącz ojca x jako ojca y if parent[x] = null then root[T] y else if x = left[parent[x]] then left[parent[x]] y else right[parent[x]] y left[y] x Przyłącz x jako lewego syna y parent[x] y 28 Przykład: Left-Rotate (1) 7 4 3 x 11 6 9 19 14 2 12 y 18 22 17 20 29 Przykład: Left-Rotate (2) 7 4 3 x 11 6 9 α 2 y 18 19 14 12 22 17 β 20 δ 30 Przykład: Left-Rotate (3) 7 4 3 2 y 18 x 11 6 19 14 9 22 α 12 17 β 20 δ 31 Przykład: Left-Rotate (4) 7 4 3 2 y 18 11 6 x 19 14 9 12 22 17 20 32