접두어로 검색
Trie의 가장 큰 장점이라고 생각하는 접두어 검색 기능이다. 단어의 일부분으로 전체단어를 검색할 수 있다. 예를들어 trie에 gold, good, gerald를 저장한 다음 검색어에 g를 입력하면 gold, good, gerald를 모두 검색할 수 있다. 이런 기능은 검색어 자동완성에 쓰인다고 한다.
우선 검색 부분의 코드를 보도록 하겠다.
우선 검색 부분의 코드를 보도록 하겠다.
def search_with_prefix(self, prefix):
words = list()
if prefix is None:
raise ValueError('Requires not-Null prefix')
top_node = self.head
for letter in prefix:
if letter in top_node.children:
top_node = top_node.children[letter]
else:
return words
if top_node == self.head:
queue = [node for key, node in top_node.children.items()]
else:
queue = [top_node]
while queue:
current_node = queue.pop()
if current_node.data is not None:
words.append(current_node.data)
queue = [node for key, node in current_node.children.items()] + queue
return words
조회 부분의 원리는 간단하다. 입력한 접두어가 저장되어 있는지 확인하고 해당 접두어가 있다면 그 접두어를 포함하고 있는 모든 단어를 반환해주는 함수이다.
여기서 queue 부분이 이해가 안갈수도 있을것 같다. 일단 queue 부분은 items()를 이용해 dict의 key, value 값, 즉 노드의 정보를 list에 담아오는 코드이다. 즉, 검색어로 입력한 단어를 포함하는 모든 단어를 찾기위해 검색어로 입력한 이후부분에 해당하는 모든 노드를 찾기 위해 노드 정보를 가져오는 것이다. 그 다음 queue.pop()을 이용해 리스트에 담겨져있는 노드정보를 꺼내 current_node에 저장하고 current_node에 데이터가 있으면 words라는 리스트에 붙이는 과정이라고 이해하면 된다.
삭제
def delete_word(self, word, depth=0):
current_node = self.head
for letter in word[:-1]:
if letter not in current_node.children:
return False
current_node = current_node.children[letter]
if current_node.NodeCount > 1:
del current_node.children[word[-1]]
return True
if word[-1] in current_node.children:
del current_node.children[word[-1]]
self.delete_word(word[:-1], depth)
return True
return False
그 다음은 삭제이다. 삭제는 삭제하고자 하는 단어를 입력하면 그 단어가 있는지 확인하고 공통 접두어가 있는 부분까지 삭제하는 방식이다. 이때 NodeCount가 사용이 되는데 NodeCount가 2 이상이면 자식 노드가 2개 이상이라는 뜻이기 때문에 그 노드에서 삭제를 멈추게하는 방식이다. 하지만 이 삭제 함수의 문제가 하나 있는데 stand와 standard를 구분하지 못한다는 것이다. standard를 삭제하면 stand는 남아있지만, stand를 삭제하면 standard도 삭제한다는 단점이 있다. 이 부분은 차후에 수정을...
if __name__ == '__main__':
trie = Trie()
trie.insert_word('good gerald gold')
print(trie.search_with_prefix('g'))
trie.delete_word('gold')
print(trie.search_with_prefix('g'))