Relájese es esencialmente correcto que hay muchas formas diferentes de implementar un trie; y para un trie grande y escalable, los diccionarios anidados pueden volverse engorrosos, o al menos ineficientes en cuanto al espacio. Pero como recién estás comenzando, creo que ese es el enfoque más fácil; podría codificar un simple trie
en solo unas pocas líneas. Primero, una función para construir el 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 no está familiarizado setdefault
, simplemente busca una clave en el diccionario (aquí letter
o _end
). Si la clave está presente, devuelve el valor asociado; si no, asigna un valor predeterminado a esa clave y devuelve el valor ( {}
o _end
). (Es como una versión de get
eso que también actualiza el diccionario).
A continuación, una función para probar si la palabra está en el 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
Te dejaré la inserción y extracción como ejercicio.
Por supuesto, la sugerencia de Unwind no sería mucho más difícil. Puede haber una ligera desventaja de velocidad en que encontrar el subnodo correcto requeriría una búsqueda lineal. Pero la búsqueda se limitaría al número de caracteres posibles: 27 si los incluimos _end
. Además, no se gana nada al crear una lista masiva de nodos y acceder a ellos por índice, como sugiere; también podrías anidar las listas.
Finalmente, agregaré que crear un gráfico de palabras acíclicas dirigido (DAWG) sería un poco más complejo, porque debe detectar situaciones en las que su palabra actual comparte un sufijo con otra palabra en la estructura. De hecho, esto puede ser bastante complejo, dependiendo de cómo desee estructurar el DAWG. Es posible que tenga que aprender algunas cosas sobre la distancia de Levenshtein para hacerlo bien.