Unwind è essenzialmente corretto sul fatto che ci sono molti modi diversi per implementare un trie; e per un trie grande e scalabile, i dizionari annidati potrebbero diventare ingombranti - o almeno inefficienti di spazio. Ma dato che hai appena iniziato, penso che sia l'approccio più semplice; potresti programmare un semplice trie
in poche righe. Innanzitutto, una funzione per costruire il 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_'}}}}
Se non hai familiarità con setdefault
, cerca semplicemente una chiave nel dizionario (qui, letter
o _end
). Se la chiave è presente, restituisce il valore associato; in caso contrario, assegna un valore predefinito a quella chiave e restituisce il valore ( {}
o _end
). (È come se una versione di get
questo aggiorni anche il dizionario.)
Successivamente, una funzione per verificare se la parola è nel 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
Lascio a voi l'inserimento e la rimozione come esercizio.
Ovviamente, il suggerimento di Unwind non sarebbe molto più difficile. Potrebbe esserci un leggero svantaggio di velocità in quanto la ricerca del sottonodo corretto richiederebbe una ricerca lineare. Ma la ricerca sarebbe limitata al numero di caratteri possibili - 27 se includiamo _end
. Inoltre, non c'è nulla da guadagnare creando un enorme elenco di nodi e accedendovi per indice come suggerisce; potresti anche semplicemente annidare gli elenchi.
Infine, aggiungerò che la creazione di un grafico di parole acicliche dirette (DAWG) sarebbe un po 'più complessa, perché devi rilevare le situazioni in cui la tua parola corrente condivide un suffisso con un'altra parola nella struttura. In effetti, questo può diventare piuttosto complesso, a seconda di come vuoi strutturare il DAWG! Potrebbe essere necessario imparare alcune cose sulla distanza di Levenshtein per farlo bene.