Morse's Site
811 字
4 分钟
Trie树
2020-07-03

Trie tree: 前缀树, 又称字典树, 是N叉树的特殊形式.

基本概念#

Trie树是用来解决一组字符串集合快速查找某个字符串的问题.

  • 数据结构

[image:999FE3AB-7090-4EAF-81D8-0037257B7FCE-894-00000DFC95BA724D/280fbc0bfdef8380fcb632af39e84b32.jpg]

* 根节点: 不包含任何信息
* 每个节点: 树中的每个节点表示一个字符串中的一个字符, 从根节点到红色节点的一条路径表示一个字符串.

注意: 红色节点并不都是叶子节点

Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起

如何表示一个前缀树#

  • 数组

用数组存储每一层的节点, 例如我们要存储的都是a~z的字母, 那么就可以声明一个长度为26的数组. 当我们要找’c’时, 就可以通过'c'-'a'的值来访问.

优势: 访问便捷 略势: 空间浪费

  • Map

用Map存储每一层的节点. key为这一层的字符, value为字符的子节点.

优势: 节省空间 略势: 比数组访问慢

补充. Trie树中, 每个节点除了存储字符外, 当需要判断当前节点是否为一个完整单词时, 需要别的字段来辅助, 比如每个节点添加一个 bool 变量, 用来判断是否为一个完整单词.

注意: 完整单词的节点不一定是叶子节点. 比如: hi, hight, 中的i, 不是叶子节点, 但是hi是一个完整的单词.

实现一个前缀树#

力扣: 208. 实现一个Trie树

package trie

type Trie struct {
	isWorld bool
	child map[byte]*Trie
}


/** Initialize your data structure here. */
func Constructor() Trie {
	return Trie{child: make(map[byte]*Trie)}
}


/** Inserts a word into the trie. */
func (this *Trie) Insert(word string)  {
	node := this
	child := this.child
	for _, char := range word {
		if c, exists := child[byte(char)]; exists {
			node = c
			child = c.child
		} else {
			node = &Trie{
				isWorld: false,
				child:   make(map[byte]*Trie),
			}
			child[byte(char)] = node
			child = node.child
		}
	}
	node.isWorld = true
}


/** Returns if the word is in the trie. */
func (this *Trie) Search(word string) bool {
	isWorld := false
	child := this.child
	for _, char := range word {
		if c, exists := child[byte(char)]; !exists {
			isWorld = false
			break
		} else {
			isWorld = c.isWorld
			child = c.child
		}
	}
	return isWorld
}


/** Returns if there is any word in the trie that starts with the given prefix. */
func (this *Trie) StartsWith(prefix string) bool {
	child := this.child
	for _, char := range prefix {
		if c, exists := child[byte(char)]; !exists {
			return false
		} else {
			child = c.child
		}
	}
	return true
}

实际应用#

前缀树广泛应用于 存储 字符串和 检索 关键字,特别是和 前缀 相关的关键字。

  1. 自动补全: 如搜索框的自动补全
  2. 拼写检查

677. 键值映射 648. 单词替换 642. 设计搜索自动补全系统 211. 添加与搜索单词 - 数据结构设计

实际应用二#

  1. 加速深度优先搜索 有时,我们会用前缀树来加速深度优先搜索。特别是当我们使用深度优先搜索解决文字游戏类问题的时候。
  2. 存储其他数据类型
  3. 还有一些其他应用,例如 IP 路由(最长前缀匹配)

421. 数组中两个数的最大异或值 212. 单词搜索 II 425. 单词方块 336. 回文对

参考#

  • 力扣(LeetCode)

#01 Blog/算法相关#

Trie树
https://fuwari.vercel.app/posts/algo/trie/
作者
Morse Hsiao
发布于
2020-07-03
许可协议
CC BY-NC-SA 4.0