Unwind jest zasadniczo poprawne, ponieważ istnieje wiele różnych sposobów realizacji próby; a w przypadku dużej, skalowalnej próby, zagnieżdżone słowniki mogą stać się nieporęczne - lub przynajmniej nieefektywne pod względem miejsca. Ale ponieważ dopiero zaczynasz, myślę, że to najłatwiejsze podejście; możesz zakodować prosty trie
w zaledwie kilku wierszach. Najpierw funkcja do skonstruowania trie:
>>> _end = '_end_'
>>>
>>> def make_trie(*words):
... root = dict()
... for word in words:
... current_dict = root
... for letter in word:
... current_dict = current_dict.setdefault(letter, {})
... current_dict[_end] = _end
... return root
...
>>> make_trie('foo', 'bar', 'baz', 'barz')
{'b': {'a': {'r': {'_end_': '_end_', 'z': {'_end_': '_end_'}},
'z': {'_end_': '_end_'}}},
'f': {'o': {'o': {'_end_': '_end_'}}}}
Jeśli nie jesteś zaznajomiony z tym setdefault
, po prostu wyszukuje klucz w słowniku (tutaj letter
lub _end
). Jeśli klucz jest obecny, zwraca skojarzoną wartość; jeśli nie, przypisuje domyślną wartość do tego klucza i zwraca wartość ( {}
lub _end
). (To tak, jakby wersja get
tego również aktualizowała słownik).
Następnie funkcja sprawdzająca, czy słowo znajduje się w trie:
>>> def in_trie(trie, word):
... current_dict = trie
... for letter in word:
... if letter not in current_dict:
... return False
... current_dict = current_dict[letter]
... return _end in current_dict
...
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'baz')
True
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'barz')
True
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'barzz')
False
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'bart')
False
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'ba')
False
Wkładanie i wyjmowanie pozostawiam tobie jako ćwiczenie.
Oczywiście sugestia Unwind nie byłaby dużo trudniejsza. Może wystąpić niewielka wada szybkości polegająca na tym, że znalezienie właściwego węzła podrzędnego wymagałoby przeszukiwania liniowego. Ale wyszukiwanie byłoby ograniczone do liczby możliwych znaków - 27, jeśli uwzględnimy _end
. Poza tym nie ma nic do zyskania tworząc ogromną listę węzłów i uzyskując do nich dostęp za pomocą indeksu, jak sugeruje; równie dobrze możesz po prostu zagnieździć listy.
Na koniec dodam, że utworzenie skierowanego acyklicznego grafu słów (DAWG) byłoby nieco bardziej złożone, ponieważ musisz wykryć sytuacje, w których twoje obecne słowo ma w strukturze przyrostek z innym słowem. W rzeczywistości może to być dość skomplikowane, w zależności od tego, jak chcesz zbudować DAWG! Być może będziesz musiał dowiedzieć się czegoś o dystansie Levenshteina, aby to naprawić.