数据结构_Trie树

Trie树

1.概述

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

图示

每个节点代表单词每一个单词的字母,打上标记的节点(红色)表示的是这个节点和他上面的所有节点构成的字母是一个单词,(从上到下),没打上标记的表示从上到下不构成一个单词。每个节点都可能有26个儿子节点,

在这里插入图片描述

2.链表模拟

2.1定义节点

力扣208.实现trie树

我们先定义每一个节点的信息,根据上面的讲述,可以知道每一个节点内部都可能有26个儿子节点,这个可以定义一个数组变量,并且有些节点还必须被标志为一个单词的结尾,这个可以定义一个布尔型的变量,记录这个节点是否是某些单词的结尾即可

注意: trie跟链表的特殊之处就是不需要定义data域,直接使用了内部的节点数组的索引,将每一个字符映射成0-25的索引

class TrieNode{
    //26个儿子节点
    TrieNode[] child;
    //标志位
    boolean isEnd;    
    public TrieNode(){
         child = new TrieNode[26];
         isEnd = false;
    }    
}

2.2增查

trie树的操作一般都是增和查,基本不进行删除和修改

class Trie {
    //根节点
    private TrieNode root;
    
    public Trie() {
       root =  new TrieNode();
    }
    
    //插入操作
    public void insert(String word) {
        TrieNode p = root;
        for(int i = 0; i < word.length(); i ++){
            char c = word.charAt(i);
            //某一个字母作为索引的节点时null,就创建出来
            if(p.child[c - 'a'] == null){
                p.child[c - 'a'] = new TrieNode(); 
            }
            //就像链表一样,p节点每次都向后移动
            p = p.child[c - 'a']; 
        }
        //单词的末尾节点的标志位置为true
        p.isEnd = true;        
    }
    
    //查询某个单词是否在trie树中
    public boolean search(String word) {
           TrieNode p = root; 
           for(int i = 0; i < word.length(); i++){ 
               char c = word.charAt(i);
               //判断这个节点是否存在,存在继续往后走
               if(p.child[c - 'a'] != null) p = p.child[c - 'a'];
               //不存在 直接返回false
               else return false;
           } 
        //注意:最后不是直接返回true,返回的是当前节点的标志位,可能即使某一个单词的所有字母都在trie树中,但是最后的节点不是某一个单词的结尾,那么表示这个单词也是不存在的
        return p.isEnd;
    }
    
    //查询是否有特定前缀的单词 思路跟查询都一样,不过最后直接返回true即可,不考虑标志位
    public boolean startsWith(String word) {
           TrieNode p = root; 
           for(int i = 0; i < word.length(); i++){ 
               char c = word.charAt(i);
               if(p.child[c - 'a'] != null) p = p.child[c - 'a'];
               else return false;
           } 
        //直接返回true
        return true;
    }
}

3.数组模拟

使用数组模拟的话没有像链表模拟好理解,使用数组模拟首先得知道数据范围,不然的话就使用链表模拟即可。

AcWing835.Trie字符串统计

import java.util.Scanner;

public class Main{
    static int N = 100010;
    private static int[][] root = new int[N][26];
    private static int[] cnt = new int[N];
    private static int idx = 0;
    
    public static void main(String[] args){
        Scanner jin = new Scanner(System.in);
        int n = jin.nextInt();
        while(n -- > 0){
            String op = jin.next();
            String str = jin.next();
            if("I".equals(op)){
                insert(str);
            }else {
                System.out.println(search(str));
            }
        }
    }
    
    public static void insert(String word){
            int p = 0;
            for(int i = 0 ; i < word.length(); i++){
                 int c = word.charAt(i) - 'a';
                 //这个位置是0 表示这个位置没有字符,为其赋一个值,每次都++idx,所以二维数组中的每一个坐标的值都不一样,即每一个坐标中存储的就是下一个字符的行数,依次进行相连
                 if(root[p][c] == 0) root[p][c] = ++idx;
                 //将这个位置上的值赋给p 
                 p = root[p][c];
            }
            //因为每一个二维数组的坐标的内容都不一样,所以可以作为唯一表示,记录以这个字母作为结尾的单词个数
            cnt[p] ++;
    }
    
    public static int search(String word){
        int p = 0;
        for(int i = 0; i < word.length(); i++){
            int c = word.charAt(i) - 'a';
            if(root[p][c]==0)return 0;
            //直接去下一个字符的下一行的对应位置去找 坐标存储的就是下一个字符的行数,每一             个坐标的内容都不一样
            else p = root[p][c];
        }
        return cnt[p];
    }
}

4.应用

力扣421.数组中的最大异或对 ——>题解
AcWing145.最大异或对

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shstart7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值