2011-11-25 13 views
12

Nie mam pojęcia, w jaki sposób implementacja Trie pozwala zaoszczędzić miejsce & przechowuje dane w najbardziej kompaktowej formie!Trie oszczędza miejsce, ale jak?

Jeśli spojrzeć na drzewo poniżej. Gdy przechowujesz znak w dowolnym węźle, musisz również zapisać odniesienie do tego &, tak aby dla każdego znaku ciągu trzeba było zachować jego odniesienie. OK, zaoszczędziliśmy trochę miejsca, gdy pojawiła się zwykła postać, ale straciliśmy więcej miejsca na przechowywanie odniesienia do tego węzła postaci.

A więc czy nie ma zbyt wiele strukturalnych kosztów utrzymania tego drzewa? Zamiast tego, gdyby zamiast tego została użyta TreeMap, powiedzmy, aby zaimplementować słownik, mogłoby to zaoszczędzić dużo więcej miejsca, ponieważ ciąg byłby przechowywany w jednym kawałku, a więc nie zmarnowałoby się miejsca na przechowywanie odniesień, prawda?

enter image description here

+0

Jeśli węzeł zajmuje 16 bajtów, ale jest ponownie wykorzystywany w więcej niż 16 ciągach (8 w Javie), oszczędza miejsce. To jest po prostu kwestia, czy zaoszczędzisz więcej miejsca niż marnujesz. Zakładając, że liczby niebieskie w twoim przykładzie liczą się powtórnie, oszczędności okazują się większe niż zmarnowana przestrzeń, w porównaniu do prostej tablicy łańcuchów. Jednak w tym przypadku byłoby jeszcze lepiej przechowywać kompletne ciągi z liczbą powtórzeń. – han

Odpowiedz

2

Można wywnioskować, że oszczędza miejsce na idealnej maszynie, gdzie każdy bajt jest przydzielany wydajnie. Jednak prawdziwe maszyny przydzielają wyrównane bloki pamięci (8 bajtów na Javę i 16 bajtów na niektórych C++), więc może nie zapisać żadnej przestrzeni.

Java Struny i kolekcje dodają stosunkowo dużą ilość nad głową, więc różnica procentowa może być bardzo mała.

O ile twoja struktura nie jest bardzo duża, o tyle, o ile chodzi o wagę czasu, koszt pamięci, który przy użyciu najprostszej, najbardziej standardowej i najłatwiejszej do utrzymania kolekcji jest o wiele ważniejszy. na przykład twój czas może bardzo łatwo być wart 1000x lub więcej wartości pamięci, którą próbujesz zapisać.

np. powiedzmy, że masz 10000 nazw, które można zapisać 16 bajtów każdy za pomocą trie. (Zakładając, że można to udowodnić, nie zabierając więcej czasu) To równa się 16 KB, która przy dzisiejszych cenach jest warta 0,1 centa. Jeśli Twój czas kosztuje firmę 30 USD za godzinę, koszt napisania jednej linii testowanego kodu może wynosić 1 USD.

Jeśli zastanawiasz się nad tym dłużej, by zaoszczędzić 16 KB, prawdopodobnie nie będzie to warte komputera. (Urządzenia mobilne są już inna historia, ale ten sam argument dotyczy IMHO)

EDIT: Ty zainspirowały mnie do dodania aktualizacji http://vanillajava.blogspot.com/2011/11/ever-decreasing-cost-of-main-memory.html

+0

Trie będzie szybszy i zaoszczędzić miejsce. W przypadku wpisów 15K może zaoszczędzić 0,2 centa pamięci i procesora. Gdybyś zobaczył, co może być 0,2 centa po drugiej stronie drogi, przejdziesz go, by go podnieść? Zrobiłbym to tylko, gdyby zajęło ci to mniej więcej sekundę. Given TreeMap to wbudowany, dobrze przetestowany dokument i zrozumiany przez każdego, kto musi obsługiwać twój kod, pozwoli ci zaoszczędzić znacznie, znacznie, dużo więcej czasu niż kosztuje w pamięci (chyba że używasz wielu urządzeń, które ograniczą pamięć) –

+1

Jeśli piszesz bibliotekę wdrożoną na tysiącach lub milionach użytkowników, te 0,2 centa mają wiele, a gdy są wdrażane na serwerach, które pobierają opłaty za używanie, te 0,2 centa mają inną wielokrotność. "Wydajność nie ma znaczenia" nie jest rozwiązaniem, jest ideologią. – Ajax

+0

Jeśli zaoszczędzisz 0,2 centa na milion maszyn, czyli łącznie 2000 USD. Warto poświęcić kilka dni, a nawet tydzień. Jeśli to tylko 100K maszyn, które patrzysz na kilka godzin lub nawet dzień. Jeśli to tylko maszyny o rozmiarze 10K, to wygląda na kilka minut. Jeśli to tylko tysiąc maszyn lub mniej, możesz zmarnować swój czas, martwiąc się o to w ogóle. Skala ma znaczenie, a większość projektów nie jest wdrażana na wystarczającej liczbie komputerów, co jest dobrym pomysłem na obawy o niewielkie ilości zasobów. –

6

Przestrzeń jest zapisywany gdy masz wiele słów, aby być reprezentowana przez drzewa. Ponieważ wiele słów ma tę samą ścieżkę na drzewie; im więcej masz słów, tym więcej miejsca zaoszczędzisz.

Ale istnieje lepsza struktura danych, jeśli chcesz zaoszczędzić miejsce. Trie nie oszczędza tak dużo miejsca, jak directed acyclic word graph (DAWG), ponieważ dzieli wspólny węzeł w całej strukturze, podczas gdy trie nie współdzieli węzłów. The wiki entry wyjaśnia tak wiele szczegółów, więc spójrz na to.

tym polega różnica (graficznie) pomiędzy Trie i psie:

enter image description here

struny "dotknij", "zawory", "góra" i "wierzchołki" przechowywane w Trie (po lewej) i DAWG (po prawej), EOW oznacza Koniec słowa.

Drzewo po lewej stronie to Trie, a drzewo po prawej to DAWG. Porównaj je i zobacz, jak DAWG oszczędza przestrzeń. Trie ma zduplikowane węzły, które reprezentują tę samą literę/podrzędne, podczas gdy DAWG ma dokładnie jeden węzeł dla każdej litery/podword.

+0

Tego nie rozumiem. Dla każdej postaci, którą oszczędzamy, płacimy cenę wskaźnika ... więc czy nie jest gorzej? – Pacerier

+0

@Pacerier: Ile razy płacisz za wskaźnik? Gdy zapłacisz za to, możesz użyć tylu powtórzeń, ile chcesz. – Nawaz

14

Aby zaoszczędzić miejsce podczas używania Trie, można użyć compressed trie (znany również jako trie patricia lub drzewa radix), dla których jeden węzeł może reprezentować wiele znaków:

w informatyce, przelicznika drzewo (również patricia trie lub radix trie) jest strukturą danych zoptymalizowaną pod kątem przestrzeni, w której każdy węzeł z jednym dzieckiem zostaje połączony z dzieckiem. W rezultacie każdy węzeł wewnętrzny ma co najmniej dwoje dzieci. W przeciwieństwie do zwykłych prób, krawędzie mogą być oznaczone ciągami znaków, jak również pojedynczymi znakami. Dzięki temu są znacznie wydajniejsze w przypadku małych zestawów (szczególnie, jeśli ciągi są długie) oraz w zestawach ciągów, które mają wspólne długie prefiksy.

Przykład drzewa Patricia:

radix tree or patricia trie

Uwaga że trie jest zwykle stosowany jako skuteczny struktury danych do dopasowywania przedrostka na zestaw strun. Trie może być również używane jako tablica asocjacyjna (jak tablica asocjacyjna), gdzie klucz jest ciągiem znaków.

+0

Spojrzałem na implementację Patricii Trie, ale czy jest to część popularnych bibliotek, takich jak Guava i Apache Commons, ponieważ są one zgodne z ich roszczeniami? Nie mogłem wymyślić jej implementacji w kolekcjach commuaw/commache –

+3

@Marcos W Guava nie ma implementacji tria, chociaż istnieje długi problem z dodawaniem, więc może się to w końcu skończyć. – ColinD

+0

Schładza. Dziękuję za wyjaśnienie! –

5

Nie chodzi o tanią przestrzeń w pamięci, chodzi o cenną przestrzeń w pliku lub łącze komunikacyjne. Z algorytmem, który buduje ten trik, możemy wysłać "dziesięć" w trzech bitach, w lewo-prawo-prawo. W porównaniu do 24 bitów "dziesięć" zajmowałoby nieskompresowane, to jest ogromna oszczędność cennego miejsca na dysku lub przepustowości transferu.

+0

to naprawdę wielka zaleta! –

+0

więc, tylko w strukturach pamięci bez konieczności przesyłania danych, ale dla wydajnego i wydajnego pod względem kosmosu rozwiązania dla uzyskania sugestii wyszukiwania dla katalogu nazw telefonicznych o 10 000 nazwach, czy używanie Trie byłoby zalecane w stosunku do TreeMap? –

1

Guava rzeczywiście mogą przechowywać klucz na każdym poziomie, ale punkt do realizacji jest to, że Klucz tak naprawdę nie musi być przechowywany, ponieważ ścieżka do węzła całkowicie definiuje klucz dla tego węzła. Wszystko, co faktycznie musi być przechowywane w każdym węźle, to pojedyncza wartość logiczna wskazująca, czy jest to węzeł liścia, czy też nie.

Próby, podobnie jak inne struktury, sprawdzają się w przechowywaniu określonych typów danych. W szczególności, najlepiej jest przechowywać ciągi, które mają wspólny katalog główny. Zastanów się, na przykład, przechowując pełne katalogi katalogów.

Powiązane problemy