Java数据结构之第十五章、Trie(前缀树/单词查找树)

简介: 1.前缀树的概念:前缀树又叫字典树或单词查找树(高效的存储和查找字符串集合的数据结构)。2.3.存储形式:存储的字符串可能:全是 小写字母 或全是 大写字母 或全是 数字 或全是 0和1。它是一棵,每个代表一个,从。字典树的根节点不包含字符,每个子节点代表一个字符,从根节点到任意一个节点所经过的路径上的字符连接起来即为该节点所代表的字符串。每个节点可以存储一个或多个字符串,通常使用一个标志来标记一个节点代表的字符串是否存在。当需要在一组字符串中查找某个字符串时,可以利用字典树来实现高效的查找操作。

 

一、前缀树

1.1前缀树相关知识

1.前缀树的概念:前缀树又叫字典树或单词查找树(高效的存储和查找字符串集合的数据结构)。

2.主要应用场景:给定一个字符串集合构建一颗前缀树,然后给定一个字符串,判断前缀树中是否包含该字符串或者该字符串的前缀。

3.存储形式:存储的字符串可能:全是 小写字母 或全是 大写字母 或全是 数字 或全是 0和1

4.字典树的核心思想是:利用字符串之间的公共前缀来节省存储空间和提高查询效率。它是一棵多叉树,每个节点代表一个字符串的前缀,从根节点到叶子节点的路径组成一个字符串。字典树的根节点不包含字符,每个子节点代表一个字符,从根节点到任意一个节点所经过的路径上的字符连接起来即为该节点所代表的字符串。每个节点可以存储一个或多个字符串,通常使用一个标志来标记一个节点代表的字符串是否存在。当需要在一组字符串中查找某个字符串时,可以利用字典树来实现高效的查找操作。

1.2前缀树的举例

    • 根结点不保存字符
    • 前缀树是一颗多叉树
    • 前缀树的每个节点保存一个字符
    • 具有相同前缀的字符串保存在同一条路径上
    • 字符串的尾处相应的在前缀树上也有结束的标志

    image.gif编辑


    二、前缀树的实现

    2.1数组实现前缀树

    2.1.1插入字符串

    private static final int[][] son=new int[100000][26];//26个字母,一共100000个数据
        private static final int[] count=new int[100000];//存储以当前这个点结尾的单词有多少个
        private int index=0;//下标为0的点,既是根节点,又是空节点
        public void insert(char[] str){
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    son[parent][cur]=++index;
                }
                parent=son[parent][cur];
            }
            count[parent]++;
        }

    image.gif

    2.1.2查找字符串

    private static final int[][] son=new int[100000][26];//26个字母,一共100000个数据
        private static final int[] count=new int[100000];//存储以当前这个点结尾的单词有多少个
        private int index=0;//下标为0的点,既是根节点,又是空节点
    public int query(char[] str){
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    return 0;
                }
                parent=son[parent][cur];
            }
            return count[parent];
        }

    image.gif

    2.1.3代码实现

    import java.util.Scanner;
    class Trie {
        private int[][] son=new int[100010][26];//26个字母,一共100000个数据
        private int[] count=new int[100010];//存储以当前这个点结尾的单词有多少个
        private int index=0;
        public Trie() {
        }
        public void insert(String word) {
            char[] str=word.toCharArray();
            //parent表示行
            int parent=0;
            for(int i=0;i<str.length;i++){
                //cur表示列,列表示字符串的开头元素
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    son[parent][cur]=++index;
                }
                parent=son[parent][cur];
            }
            count[parent]++;
        }
        public boolean search(String word) {
            char[] str=word.toCharArray();
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    return false;
                }
                parent=son[parent][cur];
            }
            return count[parent]!=0;
        }
        public boolean startsWith(String prefix) {
            char[] str=prefix.toCharArray();
            int parent=0;
            for(int i=0;i<str.length;i++){
                int cur=str[i]-'a';
                if(son[parent][cur]==0){
                    return false;
                }
                parent=son[parent][cur];
            }
            return true;
        }
    }

    image.gif

    2.2哈希表实现前缀树

    2.2.1插入字符串

    public void insert(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        trie.next.put(c, new Trie());//创建当前结点
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                trie.isEnd = true;
            }

    image.gif

    2.2.2查找字符串

    public boolean search(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return trie.isEnd;
            }

    image.gif

    2.2.3查找前缀

    public boolean startsWith(String prefix) {
                Trie trie = this;//获得根结点
                for (char c : prefix.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return true;
            }

    image.gif

    2.2.4代码实现

    public class Trie {
            Map<Character, Trie> next;
            boolean isEnd;
            public Trie() {
                this.next = new HashMap<>();
                this.isEnd = false;
            }
            public void insert(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        trie.next.put(c, new Trie());//创建当前结点
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                trie.isEnd = true;
            }
            public boolean search(String word) {
                Trie trie = this;//获得根结点
                for (char c : word.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return trie.isEnd;
            }
            public boolean startsWith(String prefix) {
                Trie trie = this;//获得根结点
                for (char c : prefix.toCharArray()) {
                    if (trie.next.get(c) == null) {//当前结点不存在
                        return false;
                    }
                    trie = trie.next.get(c);//得到字符c的结点,继续向下遍历
                }
                return true;
            }
        }

    image.gif

    目录
    相关文章
    |
    2月前
    |
    存储 算法 Java
    Java数据结构与算法-java数据结构与算法(二)
    Java数据结构与算法-java数据结构与算法
    99 1
    |
    2天前
    |
    Java
    数据结构奇妙旅程之二叉平衡树进阶---AVL树
    数据结构奇妙旅程之二叉平衡树进阶---AVL树
    |
    4天前
    |
    算法
    数据结构与算法-AVL树入门
    数据结构与算法-AVL树入门
    8 0
    |
    4天前
    |
    算法
    数据结构与算法-Trie树添加与搜索
    数据结构与算法-Trie树添加与搜索
    5 0
    |
    5天前
    |
    存储 安全 Java
    Java程序员必须掌握的数据结构:HashMap
    HashMap底层原理实现是每个Java Boy必须掌握的基本技能,HashMap也是业务开发每天都需要遇到的好伙伴。如此基础且核心的底层数据结构,JDK也给其赋予了线程安全的功能,我们来看看~
    21 1
    Java程序员必须掌握的数据结构:HashMap
    |
    6天前
    |
    存储 安全 Java
    Java并发编程中的高效数据结构:ConcurrentHashMap解析
    【4月更文挑战第25天】在多线程环境下,高效的数据访问和管理是至关重要的。Java提供了多种并发集合来处理这种情境,其中ConcurrentHashMap是最广泛使用的一个。本文将深入分析ConcurrentHashMap的内部工作原理、性能特点以及它如何在保证线程安全的同时提供高并发性,最后将展示其在实际开发中的应用示例。
    |
    12天前
    |
    存储 供应链 Java
    《Java 简易速速上手小册》第3章:Java 数据结构(2024 最新版)
    《Java 简易速速上手小册》第3章:Java 数据结构(2024 最新版)
    8 1
    |
    13天前
    |
    算法 DataX
    二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
    二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
    |
    18天前
    |
    Java API
    编码的奇迹:Java 21引入有序集合,数据结构再进化
    编码的奇迹:Java 21引入有序集合,数据结构再进化
    16 0
    |
    2月前
    |
    XML 存储 算法
    Java数据结构与算法-java数据结构与算法(五)
    Java数据结构与算法-java数据结构与算法
    49 0