Unwind est essentiellement correct qu'il existe de nombreuses façons différentes de mettre en œuvre un trie; et pour un trie volumineux et évolutif, les dictionnaires imbriqués peuvent devenir encombrants - ou du moins peu efficaces en termes d'espace. Mais puisque vous ne faites que commencer, je pense que c'est l'approche la plus simple; vous pouvez coder un simple trie
en quelques lignes. Tout d'abord, une fonction pour construire le 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_'}}}}
Si vous n'êtes pas familier avec setdefault
, il recherche simplement une clé dans le dictionnaire (ici, letter
ou _end
). Si la clé est présente, elle renvoie la valeur associée; sinon, il attribue une valeur par défaut à cette clé et renvoie la valeur ( {}
ou _end
). (C'est comme une version deget
qui met également à jour le dictionnaire.)
Ensuite, une fonction pour tester si le mot est dans le 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
Je vous laisse l'insertion et le retrait comme un exercice.
Bien sûr, la suggestion de Unwind ne serait pas beaucoup plus difficile. Il pourrait y avoir un léger inconvénient de vitesse en ce que la recherche du sous-nœud correct nécessiterait une recherche linéaire. Mais la recherche serait limitée au nombre de caractères possibles - 27 si nous incluons _end
. De plus, il n'y a rien à gagner en créant une liste massive de nœuds et en y accédant par index comme il le suggère; vous pouvez tout aussi bien imbriquer les listes.
Enfin, j'ajouterai que créer un graphe de mot acyclique dirigé (DAWG) serait un peu plus complexe, car vous devez détecter les situations dans lesquelles votre mot actuel partage un suffixe avec un autre mot dans la structure. En fait, cela peut devenir assez complexe, selon la façon dont vous souhaitez structurer le DAWG! Vous devrez peut-être apprendre des choses sur la distance de Levenshtein pour bien faire les choses.