Unwind 는 trie를 구현하는 여러 가지 방법이 있다는 점에서 본질적으로 정확합니다. 확장 가능한 대규모 트라이의 경우 중첩 된 사전이 번거 롭거나 최소한 공간 비효율적 일 수 있습니다. 하지만 이제 막 시작했기 때문에 이것이 가장 쉬운 접근 방법이라고 생각합니다. 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_'}}}}
에 익숙하지 않은 경우 setdefault
사전에서 키를 조회합니다 (여기 letter
또는 _end
). 키가 있으면 관련 값을 반환합니다. 그렇지 않은 경우 해당 키에 기본값을 할당하고 값 ( {}
또는 _end
)을 반환합니다 . ( get
사전을 업데이트 하는 버전과 같습니다 .)
다음으로 단어가 트라이에 있는지 테스트하는 함수 :
>>> 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
삽입과 제거는 운동으로 맡기겠습니다.
물론 Unwind의 제안은 그다지 어렵지 않을 것입니다. 올바른 하위 노드를 찾는 데 선형 검색이 필요하다는 점에서 약간의 속도 단점이있을 수 있습니다. 그러나 검색은 가능한 문자 수로 제한됩니다 _end
. 또한 그가 제안한대로 방대한 노드 목록을 만들고 인덱스로 액세스하여 얻을 수있는 것은 없습니다. 목록을 중첩하는 것이 좋습니다.
마지막으로, 현재 단어가 구조에서 다른 단어와 접미사를 공유하는 상황을 감지해야하기 때문에 DAWG (directed acyclic word graph)를 만드는 것이 조금 더 복잡 할 것이라고 덧붙일 것입니다. 사실, 이것은 DAWG를 어떻게 구성하고 싶은지에 따라 다소 복잡해질 수 있습니다! Levenshtein 거리 에 대해 제대로 알아 보려면 몇 가지를 배워야 할 수도 있습니다 .