Temat: Drzewa trie
Transkrypt
Temat: Drzewa trie
Temat: Drzewa trie 1. Definicja drzewa trie Drzewo trie (z ang. retrieval) to prefiksowe drzewo wielokierunkowe słu ce do zapami tania zbioru słów nad pewnym ustalonym alfabetem. Kluczem wyszukiwania w drzewie trie jest prefiks słowa, a nie całe słowo. Relacj porównywania kluczy w drzewie trie jest porz dek leksykograficzny porównywanych prefiksów. • Danymi w drzewie trie s słowa znajduj ce si w li ciach. • W zły wewn trzne to tablice wska ników do poddrzew trie. Na ka dym poziomie i sprawdzamy w tablicy indeks odpowiadaj cy i-tej literze przetwarzanego słowa. Je li wska nik na tej pozycji jest pusty, to danego słowa nie ma w drzewie. Je li wska nik jest niepusty, to kontynuujemy przetwarzanie a do osi gni cia li cia zawieraj cego szukane słowo. • W ka dym w le u ywamy dodatkowo specjalnego znaku, nie wyst puj cego w adnym słowie (w przykładach jest to znak „#”). Podczas poszukiwania na przykład słowa „ARE” po przetworzeniu znaków „A”, „R”, „E” znajdziemy si na czwartym poziomie drzewa trie, w w le, którego synami s li cie „ARE” i „AREA”. Poniewa przetworzyli my ju wszystkie litery klucza „ARE”, sprawdzamy wska nik odpowiadaj cy ko cowi słowa, czyli „#”, a skoro jest on niepusty, wnioskujemy, e słowo nale y do struktury. 1 Przykład 1 Drzewo trie dla przykładowego zbioru słów nad alfabetem : A, E, I, P, R # A E I # A E I # A P R E # A I P R E E R I E A # A E A R A A R E A R E A I E I P R E I R E P R # A E # A E E R A E R E I P R E R I E P R I P R I P A I R E # A E # A E I P E A R P E E R I P R P R P E R # A E P I E R # A I E P R I P R R E P R E A R • Wysoko drzewa trie wyznacza najdłu szy wspólny prefiks, a dokładnie wysoko ta wynosi najdłu szy wspólny prefiks +1. Dla wi kszo ci słów w j zyku angielskim operacja wyszukiwania w drzewie trie ko czyłaby po odwiedzeniu kilku w złów, zapewne 5-7. Byłoby to prawd tak dla 10000 słów, jak i dla 100000. Odpowiednie wywa one drzewo poszukiwa binarnych (np. drzewo AVL) dla 10000 słów miałoby wysoko lg 10000 = 14. Poniewa wi kszo słów le ałaby na najni szych poziomach tego drzewa, podczas wyszukiwania rednio odwiedzałoby si 13 w złów. Jest to dwukrotnie wi cej ni dla drzewa trie. 2 • W drzewie poszukiwa binarnych jest porównywany cały szukany klucz z kluczem w bie cym w le, podczas gdy w drzewie trie w porównywaniu bior udział tylko pojedyncze znaki. 2. Operacja wstawiania słowa do drzewa trie Ze wzgl du na fakt, e drzewo trie zawiera dwa rodzaje w złów, wstawianie do niego klucza jest nieco bardziej skomplikowane ni wstawianie klucza do drzewa poszukiwa binarnych. Przykład 2 Drzewo trie przed wstawieniem słowa „REP” # A E I # A E I P R # A E I P R # A E P R I P R # A E I P R R E A R # A E I P R E E R I E A # A E A R A A R E A R E A I P R E I R E # A E E R A E R E I P R E R I E I P A I R E # A E I P E A R P E E R P R P I E R P E R 3 Zakładamy, e wstawiamy do słownika wył cznie słowa niepuste. Wywołanie algorytmu wstawiania powinno by poprzedzone sprawdzeniem, czy słowa wstawianego nie ma ju w drzewie. Przykład 3 Drzewo trie po wstawieniu słowa „REP” # A E I # A E I P R # A E I P R # A E P R I P R # A E I P R # A E I P R p # A E I P R E E R I E A # A E A R A A R E A R E A I P R E I R E # A E E R A E R E I P R E R I E I P A I R E # A E I P E A R P E E R P R P E R P I E R # A E I P R R E P R E A R K_L 4 K TrieInsert (K) // K - słowo wstawiane, r – korze drzewa trie, i = 0; // ptrs – tablica wska ników na w zły potomne w w złach p = r; // wewn trznych wstawiony=0; while (!wstawiony) { if (K [i] == ‘ \ 0 ‘ ) { utwórz li L zawieraj cy K; p->ptrs[#]=L; wstawiony=1; } else if (p->ptrs[K[i]] == NULL) { utwórz li L zawieraj cy K; p->ptrs[K[i]]=L; wstawiony=1; } else if (w zeł p->ptrs[K[i]] jest li ciem) { K _ L = klucz w li ciu p->ptrs[K[i]]; zwolnij pami dla li cia p-> ptrs[K[i]]; while (K[i] == K _ L[i]) { utwórz w zeł wewn trzny N; p->ptrs[K[i]]=N; p =N; i++; }; utwórz li L zawieraj cy K; p->ptrs[K[i]]=L; if (K [i] == ‘ \ 0 ‘) { utwórz li L zawieraj cy K; p->ptrs[0]=L; wstawiony=1; } else { utwórz li L zawieraj cy K _ L; p->ptrs[K_L[i]]=L; wstawiony=1; } } else p = p->ptrs[K[i++]]; } 5 • Dla drzew trie kolejno wstawiania kluczy jest nieistotna, decyduje ona natomiast o kształcie drzew poszukiwa binarnych. 3. Drzewa trie optymalne pami ciowo Główny problem zwi zany z drzewami trie to wielko pami ci, której potrzebuj . Znacz ca jej cz jest w zasadzie marnowana. Wiele w złów mo e zawiera zaledwie kilka niepustych wska ników, a pozostałe, mimo, e s puste, musz zajmowa pami . a) Drzewo trie, w którego li ciach znajduj si tylko nie przetworzone sufiksy Przykład 4 Drzewo trie, w którego li ciach zapami tane s tylko sufiksy słów # A E I P R # A E I P R # A E I P R # A E I P R \0 # A E I P R \0 \0 R I E R E # A E I P R # A E I P R \0 \0 E A I # A E I P R # A E I P R R R P E R # A E I P R E R # A E I P R R \0 \0 6 b) Drzewo trie z dynamicznymi w złami wewn trznymi Jednym ze sposobów zmniejszenia rozmiaru w zła jest zapisywanie tylko tych wska ników, które s faktycznie u ywane. Jeden w zeł drzewa trie odpowiada teraz li cie. Przykład 5 Drzewo trie z dynamiczn struktur w zła A # A R / A E E / E E R I E A R A # A R A E E I R E A / I I A R / E E R A E R E A R E A P P R / I / I I P R A E E R I E R / A P E A R E E P E E R I / R / P E R P I E R E / A R E A R P / R E P c) Drzewo trie typu a tergo Inn metod redukcji wymaga pami ciowych jest zmiana sposobu sprawdzania słów. Do drzewa trie a tergo (z łac.: od tyłu) s wstawiane słowa odwrócone. Drzewo trie a tergo reprezentuj ce takie słowa, jak „logged”, „loggerhead”, „loggia”, „logging”, miałoby li cie na trzecim poziomie, a nie na siódmym, jak w zwykłym drzewie trie. 7 Dla pewnych cz sto spotykanych ko cówek, jak angielskie „tion”, „ism”, czy „ics”, problem pojawiłby si znowu. 4. Kompresja drzewa trie Przykład 6 Sposoby kompresji drzewa trie # A E P1 # A E P3 I P I P R P2 R # A E P6 P4 P5 I P P7 R (a) (a) TrieNodes CellArray P1 1 2 3 P3 P2 P4 P5 P6 P7 (b) TrieNodes CellArray P1 P6 1 2 3 P7 P2 P3 P4 P5 (c) 8 Innym sposobem oszcz dzania pami ci jest kompresja drzewa trie. W jednej z metod tworzy si jedn du tablice ze wszystkich tablic w w złach wewn trznych, przeplataj c je tak, by wska niki si nie nało yły. Pozycje pocz tkowe tych tablic s zapami tane w tablicy pomocniczej. Na przykład trzy w zły pokazane w przykładzie 6 na rysunku (a), zawieraj ce wska niki od p1 do p 7 do innych w złów drzewa trie (w tym li ci), s kolejno umieszczane w jednej tablicy tak, by nie spowodowa konfliktu. Powstaje pytanie, jak zrobi to efektywnie ze wzgl du na czas i pami , tak by algorytm był szybki, a powstała tablica zajmowała istotnie mniej miejsca ni wszystkie w zły wewn trzne w sumie. W przykładzie 6 na rysunku (a) na w zły potrzeba 3*6 = 18 komórek pami ci, a tablica zajmuje 11 komórek, współczynnik kompresji wynosi wi c (18 - 11)/18, czyli 39%. Je li jednak umie ci w zły w sposób pokazany na rysunku 4c, to współczynnik ten wyniesie (18 - 10)/18, a wi c 44%. Okazuje si , e algorytm słu cy kompresji drzewa wg sposobu (c) w Przykładzie 6 jest wykładniczy ze wzgl du na liczb w złów i nie daje si stosowa do du ych drzew. Inne algorytmy mog nie dawa optymalnego współczynnika kompresji, s jednak szybsze. Jednym z takich algorytmów jest CompressTrie (). CompressTrie () // NodeNum – liczba w złów drzewa, // CellNum – rozmiar alfabetu słów +1 // CellArray – tablica z adresami wszystkich w złów drzewa trie wpisz warto NULL do wszystkich NodeNum*CellNum komórek tablicy CellArray; dla ka dego w zła node dla ka dej pozycji j w tablicy CellArray if (po nało eniu pól w zła node na komórki CellArray[j], . . . , CellArray[j+CellNum-1] nie naszły na siebie adne komórki zawieraj ce wska niki) { skopiuj wska niki z node do odpowiadaj cych im komórek, zaczynaj c od CellArray[j]; 9 zapisz j w tablicy TrieNodes jako pozycj w zła node w tablicy CellArray; break; } Ten wła nie algorytm został zastosowany do drzewa trie z rysunku (a) w przykładzie 6 w celu otrzymania tablicy na rysunku (b) tego przykładu. Przeszukiwanie tak skompresowanego drzewa trie jest bardzo podobne do przeszukiwania zwyczajnego drzew trie. Dost p do w złów odbywa si jednak za po rednictwem tablicy TrieNodes. Je li w zeł node1 jest poł czony z node2 , to trzeba odnale pozycj node2 w tej tablicy, a nast pnie mo na si ga do pól w zła node2 w tablicy CellArray. Problem przy korzystaniu ze skompresowanego drzewa trie polega na tym, e poszukiwanie mo e wywie nas na manowce. Na przykład poszukiwanie słowa zaczynaj cego si od litery P w drzewie trie na rysunku (a) z przykładu 6 zostałoby natychmiast przerwane, poniewa pole wska nikowe odpowiadaj ce tej literze w korzeniu jest równe NULL. Z kolei w skompresowanej wersji tego samego drzewa trie (rysunek (b)) w polu odpowiadaj cym literze P znajduje si wska nik P3. Bł dna cie ka zostałaby wykryta pó niej po napotkaniu wska nika równego NULL lub po osi gni ciu li cia, przy porównaniu klucza w tym li ciu szukanym. Kolejnym sposobem kompresji jest utworzenie struktury zwanej Ctrie, b d cej bitow wersj zwykłego drzewa trie. W metodzie tej w zły na jednym poziomie drzewa C-trie s umieszczane w kolejnych miejscach w pami ci, a adresy pierwszych w złów na ka dym poziomie s przechowywane w tablicy adresów. Informacja przechowywana w konkretnych w złach pozwala na dost p do synów tych w złów przez obliczenie przesuni cia od nich do ich synów. 10 Przykład 7 Drzewo C-trie # AE IP R 0 0 1 1 1 1 1 0 # AE IP R # AE IP R 0 110 0 0 0 1 0 0 0 0 1 1 0 1 1 0 0 0 0 0 1 1 4 0 0 0 1 1 0 0 6 0 00 0 1 0 0 0 8 0 01 1 0 0 0 01 0 1 0 1 01 1 1 0 0 2 1 1 I P A 1 1 I R E 0 0 0 1 1 0 0 5 ... E E R IE EIRE Czy li ? # A E I P R pole C: ł czna liczba jedynek w polu K we wszystkich w złach tego samego poziomu drzewa poprzedzaj cych dany w zeł Ka dy w zeł ma cztery pola: znacznik li /w zeł wewn trzny, pole z informacj , czy to koniec słowa (pełni ce te sam funkcj co wcze niej znak #), pole K składaj ce si z CellNum bitów odpowiadaj cych komórkom ze znakami oraz pole C zawieraj ce ł czn liczb jedynek we wszystkich polach K w złów na tym samym poziomie poprzedzaj cych dany. Ta ostatnia liczba stanowi liczb w złów na nast pnym poziomie poprzedzaj cych pierwszego syna danego w zła. 11 W li ciach s przechowywane same klucze (albo ich sufiksy), je eli mieszcz si w polach K i C razem. Je li nie, to klucz jest umieszczany w osobnej tablicy, a li zawiera wska nik do jego pozycji w tej tablicy. Do odró nienia tych dwóch przypadków słu y znacznik ko ca słowa. Wszystkie w zły s tego samego rozmiaru. Zakładamy, e li mo e pomie ci do trzech znaków. Aby wyszuka klucz w strukturze C-trie, trzeba bardzo uwa nie wylicza przesuni cia. Oto zarys algorytmu: CTrieSearch (K) for (i = 1, p = korze ; ; i++) if p jest li ciem if K jest równy kluczowi p return sukces; else return pora ka; else if (K [i] == ‘ \ 0 ‘ ) if znacznik ko ca słowa jest wł czony return sukces; else return pora ka; else if bit odpowiadaj cy znakowi K[i] jest zerem return pora ka; else p = adres pierwszego w zła na poziomie (i+1) + (pole C w zła p)*(rozmiar jednego w zła) + (liczba jedynek w polu K w zła p na lewo od bitu odpowiadaj cego K[i])*(rozmiar w zła); Aby na przykład znale słowo „EERIE” w C-trie na rysunku powy ej sprawdzamy najpierw w korzeniu bit odpowiadaj cy pierwszej literze – „E”. Poniewa jest on równy 1, a korze nie jest li ciem, idziemy na drugi poziom. Adres w zła do sprawdzenia na poziomie drugim wyznaczamy, dodaj c do adresu pierwszego w zła na tym poziomie długo jednego w zła, aby go przeskoczy . Bit tego w zła wewn trznego odpowiadaj cy drugiej literze naszego słowa, równie „E”, jest równy 1, idziemy wi c na poziom trzeci. Adres w zła do sprawdzenia obliczamy, dodaj c do adresu pierwszego w zła na poziomie trzecim rozmiar jednego w zła (pierwszego w zła na 12 poziomie trzecim). Dochodzimy teraz do li cia ze znacznikiem ko ca słowa równym 0. Si gamy wi c do tablicy słów, aby porówna przechowywany w niej klucz z szukanym. Kompresja jest znaczna. Jeden w zeł pierwotnego drzewa trie o 27 dwubajtowych wska nikach zajmuje 54 bajty. Na jeden w zeł struktury C-trie potrzeba 1 + 1 + 27 + 16 = 45 bitów, co mo na pomie ci w 6 bajtach. Nie dostajemy tego jednak za darmo. Algorytm wymaga umieszczania w złów jednego poziomu ciasno obok siebie, a zapisywanie w złów po jednym na raz z u yciem funkcji ma11oc() nie gwarantuje, e b d one znajdowa si na s siaduj cych pozycjach, zwłaszcza w rodowisku z wieloma u ytkownikami. W zły jednego poziomu musz zatem by tworzone najpierw w tymczasowym pomocniczym obszarze, a dopiero potem mo na za da przydzielenia fragmentu pami ci dostatecznie du ego, aby pomie ci wszystkie te w zły. Problem ten pokazuje tak e, e struktura C-trie kiepsko nadaje si do dynamicznej aktualizacji. Je li drzewo trie jest tworzone tylko raz, to C-trie jest jego doskonale nadaj cym si do wykorzystania wariantem. Je li natomiast potrzebna jest cz sta aktualizacja, to t technik kompresji drzewa trie nale ałoby wykluczy . Przykładem zastosowania drzewa trie jest moduł sprawdzania pisowni w edytorach tekstu. 13