算法总结四:Trie到底有什么好处?

1.Trie是什么?

Trie,取自“retrieval”检索,又称前缀树或字典树,是一种有序树,,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。
In computer science, a trie, also called digital tree or prefix tree, is a kind of search tree—an ordered tree data structure used to store a dynamic set or associative array where the keys are usually strings. Unlike a binary search tree, no node in the tree stores the key associated with that node; instead, its position in the tree defines the key with which it is associated; i.e., the value of the key is distributed across the structure. All the descendants of a node have a common prefix of the string associated with that node, and the root is associated with the empty string. (from wikipedia)

在这里插入图片描述

2.有什么性质?
从图中可以明确看出:
a.根节点为空
b.节点中没有字符,字符是在路径上的。经过即得。
c.每个节点下方,最多有26中可能,每个节点分支节点都是独特的。
d.为了使用方便,通常为组成有效单词的节点“染色”,标记“isWord”。

  class TrieNode{
   
        TrieNode[] children=new TrieNode[26];
        boolean isWord;
  }

3.有什么好处?

优点是速度快,Trie树的查询复杂度在最差情况下是 O(length(input)),Hash 只能做到在平均情况下 O(length(input))

Trie的应用,通过建树的方式,用空间换取了时间。如此一来,搜索中出现大量重复的单词,不用每次一一匹配每一个char。
不过,

当字符串数量多的时候,比二叉树和哈希表更省空间。 可以做前缀比较,重要功能之一是用来做输入提示。(from zhihu

比如搜索dog和dogs,d-o-g部分不用重复存储。
insert/delete/find都是o(m), m是word的长度。

它的核心思想就是通过最大限度地减少无谓的字符串比较,使得查询高效率,即「用空间换时间」,再利用共同前缀来提高查询效率。
from知乎

5.如何build Trie?
There are two ways: to build the TrieNode
one use arrays: TrieNode[]children
node.children[w.charAt(i)-‘a’];
one use map: Map<char,TrieNode>
node.children.get(char);可以查看是否存在相应的TrieNode

    class TrieNode{
   
        TrieNode[] children=new TrieNode[26];
        boolean isWord;
    }
    
    private TrieNode buildTrie(String[] words){
   
             TrieNode root=new TrieNode();
             for(String w:words){
   
                 TrieNode cur=root;

                 for(int i=0;i<w.length();i++){
   
                     TrieNode next=cur.children[w.charAt(i)-'a'];
                     if(next==null){
   //next在图中不存在
                         next=new TrieNode();//扔一块空石头
                         cur.children[w.charAt(i)-'a']=next;//安插入队
                     }
                     cur=next;//无论是新加一个node还是原来途中有,都需要往下走
                 }
                 cur.isWord=true;
             }
             return root;
     }
         //https://leetcode.com/problems/implement-trie-prefix-tree/discuss/58832/AC-JAVA-solution-simple-using-single-array/200487/

利用Map来建设Trie

class TrieNode {
   
    Map<Character, TrieNode> children = new HashMap();
    boolean word = false;
    public TrieNode() {
   }
}

class WordDictionary {
   
    TrieNode root;
    /** Initialize your data structure here. */
    public WordDictionary() {
   
        root = new TrieNode();
    }
    /** Adds a word into the data structure. */
    public void addWord(String word) {
   
        TrieNode node = root;
        for (char ch : word.toCharArray()) {
   
            if (!node.children.containsKey(ch)) {
   //next在图中不存在
                node.children.put(ch, new TrieNode());//安插入队
            }
            node = node.children.get(ch);//往下走
        }
        node.word = true;
    }
}

from leetcode

Trie树的插入操作

Trie树的插入操作很简单,其实就是将单词的每个字母逐一插入 Trie树。插入前先看字母对应的节点是否存在,存在则共享该节点,不存在则创建对应的节点。比如要插入新单词cook,
就有下面几步:
插入第一个字母 c,发现 root 节点下方存在子节点 c, 则共享节点 c
插入第二个字母 o, 发现 c 节点下方存在子节点 o,则共享节点 o
插入第三个字母 o,发现 o 节点下方不存在子节点 o,则创建子节点 o
插入第四个字母 k,发现 o 节点下方不存在子节点 k,则创建子节点 k
至此,单词 cook 中所有字母已被插入 Trie树 中,然后设置节点 k 中的标志位,标记路径 root->c->o->o->k这条路径上所有节点的字符可以组成一个单词cook。

在这里插入图片描述

Trie树的查找操作

在 Trie 树中查找一个字符串的时候,比如查找字符串 code,可以将要查找的字符串分割成单个的字符 c,o,d,e,然后从 Trie 树的根节点开始匹配。
如果要查找的是字符串cod(鳕鱼)呢?
还是可以用上面同样的方法,从根节点开始,沿着某条路径来匹配,如图所示,绿色的路径,是字符串cod匹配的路径。但是,路径的最后一个节点「d」并不是橙色的,并不是单词标志位,所以cod字符串不存在!
条件:这个char存在路径中,是单词的最后一个char,标志位true,

class TrieNode{
   
	Map<Character, TrieNode> children = new HashMap();
    boolean isword 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值