前缀树

简介: 前缀树

概述

举个例子,给出一些单词,(andasatcncom),则其字典树如下:

网络异常,图片无法展示
|

前缀树有三个基本性质:

  • 1)根结点不包含字符,除根结点外每一个结点都只包含一个字符。
  • 2)从根结点到某一结点,路径上经过的字符连接起来,为该结点对应的字符串。
  • 3)每个结点的所有子结点包含的字符都不相同。

适用场景

  • 1)词频统计:例如,给定一个由 10 万个单词组成的库,现要你判断一个单词是否有在库中出现,若出现,求总共出现多少次或者求第一次出现在哪个位置。(如果我们使用一般的方法,每次查询一个单词都去遍历一遍,那么时间复杂度将为O(n^2),这对于大数据是不能够接受的。假如我们要查找单词student。那我们通过前缀树只需要查找s开头的即可,然后接下来查询t开头的即可,对于大量的数据可以省去不小的时间。)
  • 2)前缀匹配:以上图为例,如果想获取所有以 "a" 开头的字符串,那么从图中可以很明显的看到是:(andasat)。因此利用这个特性,可以巧妙地实现搜索提示功能,如输入一个网址,可以自动列出可能的选择。当没有完全匹配的搜索结果,可以列出前缀最相似的可能。
  • 3)游戏中的敏感词过滤

算法思路

1.设计Trie节点思路

在设计一棵树时,先要设计其节点结构。Trie需要判断当前节点是以前缀还是单词结尾,所以需要一个布尔字段来标记。由于常规情况下只考虑a~z的字母,因此只有26个字母,即最多有26个指向子节点的链接,因此可以用大小为26的数组来表示26个字母,也可以用哈希表键值对来表示。

2.insert方法

insert方法需要从根节点往下搜索。如果已经存在对应节点,沿着指针移动到子节点,继续处理下一个字符;如果不存在对应节点,那么创建一个新的节点,记录在children数组的对应位置,然后沿着指针移动到子节点,继续搜索下一个字符。重复,直到处理完字符串的最后一个字符,然后将当前节点标记为字符串结尾

3.search与startsWith方法

search同样适用DFS深度优先遍历的思想。如果能够到达搜索单词的结尾,并且此时指向的节点的布尔标记是True,则返回正确;如果搜索中途出现节点值不一致或到达单词结尾所指向的节点的布尔标记是False,则返回错误 startsWith和search的区别在于前者只要遍历途中不存在不一致的节点,无需判断布尔标记,就返回正确。

代码实现

public class TrieTree{
    public static class TrieNode{
        public int pass;
        public int end;
        public TrieNode[] nexts;
        public TrieNode(){
            pass = 0;
            end = 0;
            nexts = new TrieNode[26];
        }
    }
    public static class Trie {
        private TrieNode root;
        public Trie(){
            root = new TrieNode();
        }
        public void insert(String word){
            if(word == null){
                return;
            }
            char[] chs = word.toCharArray();
            TrieNode node = root;
            node.pass++;
            int index = 0;
            for(int i = 0; i<chs.length; i++){    // 从左往右遍历字符
                index = chs[i] - 'a';             // 由字符,对应成走向哪条路
                if(node.nexts[index]==null){
                    node.nexts[index] = new TrieNode();
                }
                node = node.nexts[index];
                node.pass++;
            }
            node.end++;
        }
        public void delete(String word){
            if(search(word)!=0){   // 确定树中确实加入过word,才删除
                char[] chs = word.toCharArray();
                trieNode node = root;
                node.pass--;
                int index = 0;
                for(int i = 0;i<chs.length; i++){
                    index = chs[i] - 'a';
                    if(--node.nexts[index].pass == 0){
                        node.nexts[index] = null;
                        return;
                    }
                    node = node.nexts[index];
                }
                node.end--;
            }
        }
    }
}
复制代码

相关Leetcode题

剑指 Offer II 062. 实现前缀树

208. 实现 Trie (前缀树)

参考链接

漫画:如何用字典树进行 500 万量级的单词统计?

游戏中的敏感词过滤算法如何实现的?


相关文章
|
4月前
哈夫曼编码和字典树
哈夫曼编码和字典树
39 0
|
4月前
|
搜索推荐
前缀树Trie
前缀树Trie
|
4月前
|
存储 C++
leetcode-208:实现 Trie (前缀树/字典树)
leetcode-208:实现 Trie (前缀树/字典树)
42 0
|
存储 自然语言处理 算法
一种好用的树结构:Trie树
一种好用的树结构:Trie树
163 0
一种好用的树结构:Trie树
理解前缀树
理解前缀树
53 0
|
存储 机器学习/深度学习 算法
|
存储
前缀树
Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
71 0
前缀树
|
机器学习/深度学习 存储 自然语言处理
Trie树
Trie树
95 0
|
存储 算法 Linux
秒懂算法 | 字典树
字典树是一种基础方法,请掌握字典树的静态数组存储方法,它在后缀树、回文树、AC自动机、后缀自动机中都要用到。
144 0
|
存储 自然语言处理 算法
字典树详解
字典树,顾名思义,是关于“字典”的一棵树。即:它是对于字典的一种存储方式(所以是一种数据结构而不是算法)。
156 0
字典树详解