数据结构——字典树Trie(介绍、Java实现)

文章目录

字典树Trie

介绍

字典树是一种专门用于处理字符串的高效数据结构,也称为前缀树或单词查找树。

定义:

字典树是一种树形数据结构,用于存储字符串集合,具有以下特点:

  • 根节点不包含字符,每个子节点代表一个字符
  • 从根节点到某一节点的路径上经过的字符连接起来,构成对应的字符串
  • 每个节点的所有子节点代表的字符都不相同

核心特性:

  • 前缀共享:具有相同前缀的字符串共享路径
  • 快速检索:查找时间复杂度与字符串长度相关,与数据量无关
  • 前缀匹配:天然支持前缀搜索

Java实现

我们了解完字典树数据结构,尝试手搓一个简化版的字典树加强理解,在这个开源项目中实现。

GitCode - 全球开发者的开源社区,开源代码托管平台

  • 节点TrieNode
java 复制代码
public class TrieNode {
    private TrieNode[] children;    // 子节点数组,一共26个
    private boolean isWord; // 是否结尾即是否是单词结尾
    public TrieNode(){
        children = new TrieNode[26];
        isWord = false;
    }
    public boolean containKey(char c){
        return children[c - 'a'] != null;
    }
    public void putChar(char c){
        children[c - 'a'] = new TrieNode();
    }
    public TrieNode getChild(char c){
        if (children[c - 'a'] == null) return null;
        return children[c - 'a'];
    }
    public void setIsWord(boolean isWord){
        this.isWord = isWord;
    }
    public boolean isWordOrNot(){
        return isWord;
    }
}
  • 字典树Trie
java 复制代码
public class Trie {
    private TrieNode root;
    /**
     * 构造函数,初始化Trie树
     * 创建一个空的根节点
     */
    public Trie() {
        root = new TrieNode();
    }

    /**
     * 插入单词到Trie树中
     * @param word 要插入的单词
     */
    public void insert(String word) {
        if(word == null || word.length() == 0) return;
        TrieNode node = root;
        // 遍历单词字母
        for(int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (!node.containKey(c)){
                node.putChar(c);
            }
            node = node.getChild(c);
        }
        node.setIsWord(true); // 设置为单词结尾
    }

    /**
     * 在Trie树中搜索指定单词
     * @param word 要搜索的单词
     * @return 如果单词存在返回true,否则返回false
     */
    public boolean searchWord(String word) {
        if(word == null || word.length() == 0) return false;
        TrieNode node = searchPrefix(word);
        return node != null && node.isWordOrNot();
    }

    /**
     * 检查Trie树中是否存在指定前缀
     * @param prefix 要检查的前缀
     * @return 如果前缀存在返回true,否则返回false
     */
    public boolean startsWith(String prefix) {
        if(prefix == null || prefix.length() == 0) return false;
        return searchPrefix(prefix) != null;
    }

    /**
     * 查找前缀对应的节点
     * @param prefix 要查找的前缀
     * @return 如果前缀存在,返回前缀最后一个字符对应的节点;否则返回null
     */
    private TrieNode searchPrefix(String prefix) {
        TrieNode node = root;
        for (int i = 0; i < prefix.length(); i++) {
            char c = prefix.charAt(i);
            if (!node.containKey(c)){
                return null;
            }
            node = node.getChild(c);
        }
        return node;
    }

    /**
     * 搜索所有以指定前缀开头的单词
     * @param prefix 搜索的前缀
     * @return 所有匹配的单词列表
     */
    public List<String> searchWordsWithPrefix(String prefix){
        if(prefix == null || prefix.length() == 0) return new ArrayList<>();
        List<String> result = new ArrayList<>();
        TrieNode node = searchPrefix(prefix);
        if(node != null){
            collectWordsStartWithPrefix(node, result, new StringBuilder(prefix));
        }
        return result;
    }

    /**
     * 递归收集以指定节点开始的所有单词
     * @param node 当前节点
     * @param result 结果列表,用于存储找到的单词
     * @param strbuilder 当前构建的字符串
     */
    private void collectWordsStartWithPrefix(TrieNode node, List<String> result, StringBuilder strbuilder) {
        if(node.isWordOrNot()){
            result.add(strbuilder.toString());
        }
        for(int i = 0;i < 26;i ++){
            char c = (char)('a' + i);
            if(node.containKey(c)){
                strbuilder.append(c);
                collectWordsStartWithPrefix(node.getChild(c), result, strbuilder);
                strbuilder.deleteCharAt(strbuilder.length() - 1); // 回溯
            }
        }
    }

    public static void main(String[] args) {
        Trie trie = new Trie();
        trie.insert("apple");
        trie.insert("application");
        trie.insert("blue");
        trie.insert("blueface");
        trie.insert("blwww");
        System.out.println(trie.searchWord("blue"));
        System.out.println(trie.searchWordsWithPrefix("app"));
        System.out.println(trie.searchWordsWithPrefix("bl"));
    }
}
  • 测试结果:
plain 复制代码
true
[apple, application]
[blue, blueface, blwww]
相关推荐
灰色小旋风22 分钟前
力扣13 罗马数字转整数
数据结构·c++·算法·leetcode
sxlishaobin30 分钟前
Java I/O 模型详解:BIO、NIO、AIO
java·开发语言·nio
彭于晏Yan36 分钟前
Spring AI(二):入门使用
java·spring boot·spring·ai
有一个好名字1 小时前
vibe codeing 开发流程
java
兑生1 小时前
【灵神题单·贪心】3745. 三元素表达式的最大值 | 排序贪心 | Java
java·开发语言
polaris06301 小时前
Windows操作系统部署Tomcat详细讲解
java·windows·tomcat
卓怡学长1 小时前
m280本科生导师指导平台
java·数据库·spring·tomcat·maven·intellij-idea
一直都在5722 小时前
Java死锁
java·开发语言
ccLianLian2 小时前
数论·欧拉函数
数据结构·算法
我真会写代码2 小时前
深度解析并发编程锁升级:从偏向锁到重量级锁,底层原理+面试考点全拆解
java·并发编程·