Drzewa: BST, kopce - Letnie Warsztaty Matematyczno
Transkrypt
Drzewa: BST, kopce - Letnie Warsztaty Matematyczno
Letnie Warsztaty Matematyczno-Informatyczne Algorytmy i struktury danych Drzewa: BST, kopce Drzewa: BST, kopce Definicja drzewa Drzewo (ang. tree) to nieskierowany, acykliczny, spójny graf. Drzewo może być ukorzenione (ang. rooted), to znaczy posiadać korzeń (ang. root) – jeden wyróżniony wierzchołek. Drzewa: BST, kopce Definicja drzewa W drzewie ukorzenionym możemy definiować relacje między wierzchołkami. Jeżeli na drodze z korzenia do jakiegoś wierzchołka u znajduje się przed v , to u jest przodkiem v , a v jest potomkiem u. Bezpośredni przodek to rodzic (ang. parent), a bezpośredni potomek to dziecko (ang. child). Wierzchołki posiadające wspólnego rodzica to bracia (ang. sibling ). Wierzchołki nieposiadające dzieci nazywamy liśćmi (ang. leaf ). Drzewa: BST, kopce Drzewa binarne Jeżeli w drzewie ukorzenionym każdy wierzchołek posiada co najwyżej 2 dzieci, to takie drzewo nazywamy binarnym (ang. binary tree). Drzewa: BST, kopce Drzewa przeszukiwań binarnych Drzewo przeszukiwań binarnych (ang. binary search tree, BST ) jest strukturą danych, będącą specjalnym przypadkiem drzewa binarnego. Każdy z wierzchołków w takim drzewie posiada przypisaną wartość. Dodatkowo ułożenie tych wartości musi być zgodne z następującą regułą: Wszystkie wartości w lewym poddrzewie danego wierzchołka muszą być mniejsze od wartości tego wierzchołka. Podobnie wszystkie wartości w jego prawym poddrzewie muszą być od wartości tego wierzchołka większe. Drzewa: BST, kopce Drzewa przeszukiwań binarnych Drzewa przeszukiwań binarnych mogą zostać użyte do zaimplementowania zbioru. Operacje Insert, Member? i Delete mają średnią złożoność obliczeniową O(log n), zaś pesymistyczną O(n). Drzewa: BST, kopce Drzewa przeszukiwań binarnych procedure Insert(T , v ) if v < T .value then if T .left = nil then T .left ← BST − Node(v ) else Insert(T .left, v ) end if else if T .right = nil then T .right ← BST − Node(v ) else Insert(T .right, v ) end if end if end procedure Drzewa: BST, kopce Drzewa przeszukiwań binarnych procedure Member?(T , v ) if T = nil then return false else if v = T .value then return true else if v < T .value then return Member?(T .left, v ) else return Member?(T .right, v ) end if end procedure Drzewa: BST, kopce Kopiec binarny Kopiec binarny (ang. binary heap) to również struktura danych będąca specjalnym przypadkiem drzewa binarnego. Tak jak w przypadku BST, wszystkie wierzchołki posiadają przypisane wartości. Oprócz tego kopiec musi być drzewem prawie pełnym, a wartości w nim muszą spełniać regułę kopca, tj. wszyscy potomkowie danego wierzchołka muszą mieć wartości większe od niego. Drzewa: BST, kopce Kopiec binarny Kopiec binarny może być użyty do zaimplementowania kolejki priorytetowej, w której operacje Insert, Extract-Minimum i Delete mają złożoność obliczeniową O(log n), a Top – O(1). Drzewa: BST, kopce Kopiec dwumianowy Kopiec dwumianowy (ang. binomial heap) jest strukturą danych opartą na lesie (ang. forest), czyli zbiorze drzew. Umożliwia implementację kolejki priorytetowej, w której operacje Insert, Extract-Minimum i Delete mają złożoność obliczeniową O(log n), Top – O(1), a do tego złączenie dwóch kopców jest możliwe w czasie O(log n) (w odróżnieniu od kopca binarnego, gdzie ta operacja zajmuje czas liniowy). Letnie Warsztaty Matematyczno-Informatyczne Algorytmy i struktury danych Wyszukiwanie wzorca w tekście Wyszukiwanie wzorca w tekście Istota problemu Mamy dane dwa ciągi znaków: tekst T (ang. haystack) i wzorzec P (ang. needle). Oba z nich są tablicami. Istotą problemu jest znalezienie wszystkich indeksów w tekście takich, że od tego miejsca tekst jest identyczny ze wzorcem (do końca wzorca). Wyszukiwanie wzorca w tekście Istota problemu Przykładowo, mając dany tekst: „abrakadabra” i wzorzec „ra”, wynikami będą 2 i 9 (pamiętaj, że indeksy zaczynają się od 0). Dla tekstu: „aaaa” i wzorca „aa”, wynikami będą 0, 1 i 2. Wyszukiwanie wzorca w tekście Algorytm naiwny Mając dany indeks możemy łatwo sprawdzić, czy jest on poprawnym rozwiązaniem, porównując kolejne znaki w T ze znakami w P. Zajmuje to czas O(|P|). Algorytm naiwny sprawdza w ten sposób każdy możliwy indeks (O(|T |) sprawdzeń), dając całkowitą złożoność obliczeniową O(|P||T |). Algorytm ten można przyspieszyć, przerywając sprawdzanie w momencie pierwszego różniącego się znaku, jednak pesymistyczna złożoność obliczeniowa zostaje taka sama. Wyszukiwanie wzorca w tekście Algorytm Rabina-Karpa Algorytm Rabina-Karpa również opiera się na sprawdzaniu możliwych indeksów, jak algorytm naiwny, jednak zmniejsza liczbę potencjalnych kandydatów, używając funkcji haszującej. Przed wykonaniem właściwego sprawdzenia obliczany jest hasz wzorca, a potem dla każdego indeksu obliczany jest hasz |P| następnych znaków. Właściwe sprawdzenie wykonywane jest tylko w momencie zgodności haszy. Wyszukiwanie wzorca w tekście Algorytm Rabina-Karpa Wydawać by się mogło, że nie poprawia to złożoności obliczeniowej (koszt liczenia haszu również wynosi O(|P|)). Istota optymalizacji polega jednak na tym, że wykorzystujemy taką funkcję haszującą, której wartość w indeksie i można szybko obliczyć na podstawie wartości w indeksie i − 1 (tzw. rolling hash). Wyszukiwanie wzorca w tekście Automaty skończone Do rozwiązania problemu wyszukiwania wzorca w tekście można użyć również automatów skończonych. Automat skończony to graf skierowany, w którym krawędzie mają dodatkowo przypisane symbole (lub grupy symboli) i nazywa się je przejściami. Wierzchołki nazywamy stanami. Jeden ze stanów jest stanem początkowym, jeden jest stanem akceptującym. Wyszukiwanie wzorca w tekście Automaty skończone Mamy dany tekst i automat skończony zbudowany na podstawie wzorca. Zaczynając od stanu początkowego, przechodzimy między stanami, wybierając przejścia zgodnie z kolejnymi znakami tekstu. Jeżeli znajdziemy się w stanie akceptującym oznacza to, że znajdujemy się w ostatnim znaku dopasowania.