geekdoc-python-zh/docs/askpython/trie-data-structure.md

288 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 用 Python 实现 Trie 数据结构
> 原文:<https://www.askpython.com/python/examples/trie-data-structure>
数据结构在信息检索方面非常有效。它主要用于实现[字典](https://www.askpython.com/python/dictionary/python-dictionary-comprehension)和电话簿。
它对于实现在键盘上键入时看到的自动文本建议也很有用。
在本教程中,我们将了解如何用 Python 实现我们自己的 trie 数据结构。
在本教程中,您将学习以下内容:
* 如何实现你自己的 Trie 数据结构。
* 如何在 Trie 数据结构中插入数据?
* 如何在 Trie 数据结构中查询单词?
## 实现 TrieNode 类
让我们从编写 **TrieNode 类**的代码开始。每个 trie 节点需要具有以下字段:
1. 一个角色
2. 儿童名单
3. 一个布尔值,它表明一个单词是否在该节点结束。
让我们为 TrieNode 类编写代码:
```py
class TrieNode:
def __init__(self, char):
self.char = char
self.is_end = False
self.children = {}
```
初始化 TrieNode 时,我们需要提供一个字符。
**。is_end** 标记一个字是否在当前节点结束。默认情况下,它被设置为 false。
## 编写 Trie 数据结构类
让我们继续为我们的 Trie 类编写代码。
要初始化一个 trie我们需要初始化一个 trie 节点,并提供在 trie 中插入和搜索的方法。
```py
class Trie(object):
def __init__(self):
self.root = TrieNode("")
```
这部分负责初始化一个空的 TrieNode。
### 如何在我们的 Trie 中执行插入操作?
让我们看看插入是如何在 Trie 数据结构中发生的。
为了进行插入,我们需要逐个字符地遍历要插入的单词。
同时,我们需要从根开始向下移动 Trie看看孩子的列表是否有那个字符。如果该字符不存在那么我们需要用该字符创建一个新的 TrieNode并将其添加到孩子列表中。
当我们到达单词的末尾时,我们需要为对应于单词最后一个字符的节点设置 **is_end** 为真。
下面是上面讨论的方法的实现。
```py
def insert(self, word):
node = self.root
#traverse the word character by character
for char in word:
#check if the character is there in the list of children
if char in node.children:
node = node.children[char]
else:
# else make a new TrieNode corresponding to that character
new_node = TrieNode(char)
# add the new node to the list of children
node.children[char] = new_node
node = new_node
#after traversig the word set .is_end to true for the last #char
node.is_end = True
```
这将照顾我们所有的插入。
考虑一个包含以下单词的 Trie:
* 这里
*
*
* 男性
* 你好
* 怎么
对应于这些单词的 trie 将如下所示:
![Trie](img/ecd4f96dd67955e450239880ab5e7297.png)
Trie
这里的**绿色节点**对应于该节点的**为真**。
### 如何在我们的 Trie 中搜索?
现在让我们看看如何在我们的特里搜索单词。我们不想为搜索执行精确匹配。相反,我们想要的是获得以我们要搜索的字符串开始的单词列表。
在搜索时,我们将只提供前缀,搜索功能应该能够返回以该前缀开始的所有单词。
例如,如果我们搜索**“他”**,我们应该得到以下单词。
* 男性
* 这里
*
*
* 你好
这些都是以“他”开头的词。trie 的这一方面使得它对于在键盘中实现自动完成非常有用。
在搜索单词时,我们以 DFS 的方式进行搜索。因此,我们需要编写一个函数,用于在我们的 trie 中执行 [DFS 搜索](https://www.askpython.com/python/examples/depth-first-search-algorithm)。
```py
def dfs(self, node, pre):
if node.is_end:
self.output.append((pre + node.char))
for child in node.children.values():
self.dfs(child, pre + node.char)
```
在调用函数时,我们需要传递一个节点和到目前为止搜索到的前缀。每当搜索到达一个节点,并且 ***为真***时,它会将该单词附加到输出列表中。
否则,它继续以 DFS 方式在子节点中搜索。
搜索功能如下:
```py
def search(self, x):
node = self.root
# traverse the search query and move down the trie
for char in x:
if char in node.children:
node = node.children[char]
else:
#if query doesn't match the nodes in trie
return []
self.output = []
#call DFS
self.dfs(node, x[:-1])
return self.output
```
在搜索时,我们遍历搜索查询并同时向下移动 trie。
然后,我们在与查询的最后一个字符对应的节点上调用 DFS。
然后DFS 函数从最后一个字符开始向下移动,将所有完整的单词添加到输出列表中。
## 完全码
本教程的完整代码如下所示:
```py
class TrieNode:
def __init__(self, char):
self.char = char
self.is_end = False
self.children = {}
class Trie(object):
def __init__(self):
self.root = TrieNode("")
def insert(self, word):
node = self.root
for char in word:
if char in node.children:
node = node.children[char]
else:
new_node = TrieNode(char)
node.children[char] = new_node
node = new_node
node.is_end = True
def dfs(self, node, pre):
if node.is_end:
self.output.append((pre + node.char))
for child in node.children.values():
self.dfs(child, pre + node.char)
def search(self, x):
node = self.root
for char in x:
if char in node.children:
node = node.children[char]
else:
return []
self.output = []
self.dfs(node, x[:-1])
return self.output
```
## 行动中的尝试
让我们试着向一个 trie 中添加一些单词,并进行搜索查询。
```py
tr = Trie()
tr.insert("here")
tr.insert("hear")
tr.insert("he")
tr.insert("hello")
tr.insert("how ")
tr.insert("her")
```
这将创建一个 trie并将这五个单词添加到其中。
现在我们可以使用下面一行进行查询:
```py
tr.search("he")
```
输出:
```py
['he', 'her', 'here', 'hear', 'hello']
```
让我们做另一个查询:
```py
tr.search("her")
```
输出:
```py
['her', 'here']
```
## 结论
本教程讲述了 Python 中 Trie 数据结构的实现。我们学习了如何创建一个 trie 类,如何执行插入,以及如何在 Trie 中查询单词。