Trie 字典树

Trie 字典树


1.1、定义

字典树,顾名思义,是关于“字典”的一棵树。即:它是对于字典的一种存储方式(所以是一种数据结构而不是算法)。这个词典中的每个“单词”就是从根节点出发一直到某一个目标节点的路径,路径中每条边的字母连起来就是一个单词。

1.2、字典树描述

其结点具有以下字段:。
最多 RR 个指向子结点的链接,其中每个链接对应字母表数据集中的一个字母。
本文中假定 RR 为 26,小写拉丁字母的数量。
布尔字段,以指定节点是对应键的结尾还是只是键前缀。
树中黄色节点表示目标节点,在此节点以上可组成一个单词

// 可获取如下字符串
a
abc
bac
bbc
ca

1.3、使用场景

字典树的本质是把很多字符串拆成单个字符的形式,以树的方式存储起来。所以我们说字典树维护的是”字典“。那么根据这个最基本的性质,我们可以由此延伸出字典树的很多妙用。简单总结起来大体如下:

  • 1、维护字符串集合(即字典)。
  • 2、向字符串集合中插入字符串(即建树)。
  • 3、查询字符串集合中是否有某个字符串(即查询)。
  • 4、统计字符串在集合中出现的个数(即统计)。
  • 5、将字符串集合按字典序排序(即字典序排序)。
  • 6、求集合内两个字符串的LCP(Longest Common Prefix,最长公共前缀)(即求最长公共前缀)。

自动补全

在这里插入图片描述

拼写检查

在这里插入图片描述

IP路由(最长前缀匹配)

打字预测

单词游戏

匹配过程

Java实现 Trie 字典树


2.1、数据结构

Java代码实现

public class TrieNode{
    // 建立数组存储子字符串(建立Node)
    private TrieNode[] links;

    // 由于一个单词(小写),最多只有26个字母
    private final int R = 26 ;
    
    //判断当前节点是否为结束节点
    private boolean isEnd;

    // 构造函数
    public TireNode(){
      links = new TrieNode[R];
    }

    public boolean containsKey(char ch) {
        return links[ch -'a'] != null;
    }
    public TrieNode get(char ch) {
        return links[ch -'a'];
    }
    public void put(char ch, TrieNode node) {
        links[ch -'a'] = node;
    }
    public void setEnd() {
        isEnd = true;
    }
    public boolean isEnd() {
        return isEnd;
    }
}

2.2、数据操作

对于树这种数据结构,很多时候我们都比较关注与两点:“查询” 与 “ 插入”数据

2.2.1、插入数据

我们通过搜索 Trie 树来插入一个键。我们从根开始搜索它对应于第一个键字符的链接。有两种情况:
补充每个键在 trie 中表示为从根到内部节点或叶的路径。
1、链接存在。沿着链接移动到树的下一个子层。算法继续搜索下一个键字符。
2、链接不存在。创建一个新的节点,并将它与父节点的链接相连,该链接与当前的键字符相匹配。
重复以上步骤,直到到达键的最后一个字符,然后将当前节点标记为结束节点,算法完成。

如图

Java代码实现

    public class Trie{
    
    private TrieNode root ;
    
    public Trie(){
        root = new TrieNoe();
    }

    // 插入数据
    public void insert(String word){
        TrieNode node = root ;
    
        for(int i=0;i<word.length() ;i++){
                char currentChar = word.charAt(i);
                if(!node.containKeys(currentChar)){
                    node.put(currentChar,new TrieNode());
                }
                node = node.get(currentChar);
            }
            node.isEnd();
        }

    }

2.2.2、查询数据

每个键在 trie 中表示为从根到内部节点或叶的路径。我们用第一个键字符从根开始,。检查当前节点中与键字符对应的链接。有两种情况:

1、存在链接。我们移动到该链接后面路径中的下一个节点,并继续搜索下一个键字符。
2、不存在链接。若已无键字符,且当前结点标记为 isEnd,则返回 true。否则有两种可能,均返回 false :
(1)、还有键字符剩余,但无法跟随 Trie 树的键路径,找不到键。
(2)、没有键字符剩余,但当前结点没有标记为 isEnd。也就是说,待查找键只是Trie树中另一个键的前缀。

如图

    public class Trie{
    
    private TrieNode root ;
    
    public Trie(){
        root = new TrieNoe();
    }

    // 查询数据,并返回结束时的Node点
    public TrieNode searchPrefix(String word){
        TrieNode node = root ; 
        for(inti = 0 ;i<word.length();i++){
            char currentChar = word.charAt(i);
            if(node.containKeys(currentChar)){
                node = node.get(currentChar);
            }else{
                return null;
            }
        }
          return node ;
    }
      

        // 判断查询结束时,返回node节点为目标节点且不为空 
        public  boolean search(String word){
            TireNode node = searchPrefix(word);
               return node !=null &&node.isEnd();
        }
    }

扩展

查询Trie树的键前缀

该方法与在 Trie 树中搜索键时使用的方法非常相似。我们从根遍历 Trie 树,直到键前缀中没有字
符,或者无法用当前的键字符继续 Trie 中的路径。与上面提到的“搜索键”算法唯一的区别是,到
达键前缀的末尾时,总是返回 true。我们不需要考虑当前 Trie 节点是否用 “isend” 标记,因为我
们搜索的是键的前缀,而不是整个键。

如图

Java代码实现


 public boolean startsWith(String prefix){
    TrieNode node = searchPrefix(prefix);
    return node!=null;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值