Algorytmy i struktury danych Drzewa: BST, kopce Letnie Warsztaty Matematyczno-Informatyczne
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).
Algorytmy i struktury danych Wyszukiwanie wzorca w tekście Letnie Warsztaty Matematyczno-Informatyczne
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.