首页 > 其他分享 >Trie树(字典树,前缀树)

Trie树(字典树,前缀树)

时间:2022-09-23 21:00:30浏览次数:67  
标签:单词 ch 前缀 parent Trie TNode char new 字典

Trie中文名又叫做字典树,前缀树等,因为其结构独有的特点,经常被用来统计,排序,和保存大量的字符串,经常见于搜索提示,输入法文字关联等,当输入一个值,可以自动搜索出可能的选择。当没有完全匹配的结果时,可以返回前缀最为相似的可能。   例如:上面的树由abcd abc abd,b等构成,红点表示可以为某个单词的尾巴,最上面的空白就是root节点(不携带值的) 常见的api有insert(将一个单词插入),search(查找是否存在某个单词),startsWith(是否是以某个单词作为前缀开头) 下面简单实现,使用search的来返回结果来告知是否是前缀或者存在此单词

class Trie {
    class TNode {
        // 孩子节点,英文的话最多26个字母,此处可以用HashMap来代替,可以处理中文场景等
        TNode[] ch = new TNode[26];
        // 是否可以为某个单词的尾巴
        boolean isEnd;
        // 当前字符内容,以下均是看使用场景,不是必须
        char v;
    }
TNode root = new TNode(); void insert(String s) { // 每次插入都要从头开始构建trie树 TNode parent = root; char[] cs = s.toCharArray(); for (char c : cs) { if (parent.ch[c - 'a'] == null) { // 新的字符,则需要新建一个节点 parent.ch[c - 'a'] = new TNode(); parent.ch[c - 'a'].v = c; } parent = parent.ch[c - 'a']; } parent.isEnd = true; } // -1是不存在或者不存在前缀,0是存在前缀,1是存在此单词 int search(String s) { TNode parent = root; char[] cs = s.toCharArray(); for (char c : cs) { if (parent.ch[c - 'a'] == null) { // 说明不存在这个字符,也就是不存在这个单词 return -1; } // 指针指向child parent = parent.ch[c - 'a']; } return parent.isEnd ? 1 : 0; } }

接下来我们实现一个简单的输入法提示:

class Trie {
    class TNode {
        // 孩子节点,英文的话最多26个字母,此处可以用HashMap来代替,可以处理中文场景等
        TNode[] ch = new TNode[26];
        // 是否可以为某个单词的尾巴
        boolean isEnd;
        // 当前字符内容,以下均是看使用场景,不是必须
        char v;
    }

    TNode root = new TNode();

    void insert(String s) {
        // 每次插入都要从头开始构建trie树
        TNode parent = root;
        char[] cs = s.toCharArray();
        for (char c : cs) {
            if (parent.ch[c - 'a'] == null) {
                // 新的字符,则需要新建一个节点
                parent.ch[c - 'a'] = new TNode();
                parent.ch[c - 'a'].v = c;
            }
            parent = parent.ch[c - 'a'];
        }
        parent.isEnd = true;
    }

    // -1是不存在或者不存在前缀,0是存在前缀,1是存在此单词
    int search(String s) {
        TNode parent = root;
        char[] cs = s.toCharArray();
        for (char c : cs) {
            if (parent.ch[c - 'a'] == null) {
                // 说明不存在这个字符,也就是不存在这个单词
                return -1;
            }
            // 指针指向child
            parent = parent.ch[c - 'a'];
        }
        return parent.isEnd ? 1 : 0;
    }

    /**
     * 返回匹配出的搜索结果集合
     */
    List<String> input(String word) {
        TNode parent = root;
        char[] cs = word.toCharArray();
        for (char c : cs) {
            if (parent.ch[c - 'a'] == null) {
                return Collections.emptyList();
            }
            parent = parent.ch[c - 'a'];
        }
        // 现在位于最后一个字母就是parent.v
        List<String> res = new ArrayList<>();
        LinkedList<Character> ss = new LinkedList<>();
        // 找到所有的尾巴
        dfs(parent, ss, res);
        // 将word(也就是头)和尾巴拼上构建最终的结果
        List<String> res2 = new ArrayList<>();
        for (String s : res) {
            res2.add(word + s);
        }
        return res2;

    }

    /**
     * 使用dfs回溯,将所有包含此前缀的单词都保存到res中
     */
    private void dfs(TNode parent, LinkedList<Character> ss, List<String> res) {
        if (parent.isEnd) {
            StringBuilder sb = new StringBuilder();
            // 将字符构建成String
            for (Character c : ss) {
                sb.append(c);
            }
            res.add(sb.toString());
        }
        for (int i = 0; i < parent.ch.length; i++) {
            if (parent.ch[i] != null) {
                ss.add(parent.ch[i].v);
                // 回溯
                dfs(parent.ch[i], ss, res);
                ss.removeLast();
            }
        }
    }
}

注意上面的input就是我们实现的英文输入提示,他根据我们的输入匹配所以可能的结果,如下测试:

    public static void main(String[] args) {
        Trie tree = new Trie();
        String[] strs = {"app", "apple", "add"};
        // 构建词库,就是构建字典树使用insert一个一个单词插入
        for (String str : strs) {
            tree.insert(str);
        }
        System.out.println(tree.input("a"));// [add, app, apple]
        System.out.println(tree.input("ap"));// [app, apple]
        System.out.println(tree.input("app"));// [app, apple]
        System.out.println(tree.input("appl"));// [apple]
        System.out.println(tree.input("dd"));// []
    }

字典树的应用非常广泛,自己动手实现一个我们每天都会接触的输入法的提示也是有点意思!

 

 

 

 

标签:单词,ch,前缀,parent,Trie,TNode,char,new,字典
From: https://www.cnblogs.com/junlancer/p/16724216.html

相关文章

  • 在Winform开发中,我们使用的几种下拉列表展示字典数据的方式
    在Winform开发中中,我们为了方便客户选择,往往使用系统的字典数据选择,毕竟选择总比输入来的快捷、统一,一般我们都会简单封装一下,以便方便对控件的字典值进行展示处理,本篇随笔......
  • 字典树-2416. 字符串的前缀分数和
    问题描述给你一个长度为n的数组words,该数组由非空字符串组成。定义字符串word的分数等于以word作为前缀的words[i]的数目。例如,如果words=["a","ab......
  • 洛谷 P1114 “非常男女”计划 (前缀和)
    https://www.luogu.com.cn/problem/P1114题目大意:给定一排数字,让我们求出最大的区间内1和0的个数相等时的区间长度。输入9010001100输出6输入10011......
  • Typescript类型体操 - ObjectEntries
    题目中文实现Object.entries的类型版本示例:interfaceModel{name:string;age:number;locations:string[]|null;}typemodelEntries=Objec......
  • 复习元组列表字典
    元组能存储多个不同类型的数据,且是有序的。但它是不可变的,因此不能进行修改、删除或添加元素的操作。列表和元组非常相似,唯一的不同是列表的元素是可以修改的。字典的元素......
  • 字典
    字典-定义:在Python中,将两种数据关联在一起形成一个元素,由多个这样的元素组成的数据类型称为字典,又称为dict。字典中的元素是不考虑排列顺序的。组成字典元素(item)的两个......
  • Python在字典中通过键名查找键值
    deffind(target,dict_data):""":paramtarget:需要查找的键名:paramdict_data:需要查找的列表:return:如果找到就返回对应键名的键值,否则提示没......
  • 字典增删改查
    #字典Dict,也称为mapping字典是可变的、无序的、key不重复的key-value键值对集合初始化:dict(**kwargs)使用name=value对初始化一个字典dict(iterable,**kwarg),使用可迭代......
  • 22张图带你深入剖析前缀、中缀、后缀表达式以及表达式求值
    22张图带你深入剖析前缀、中缀、后缀表达式以及表达式求值一、基本概念在本篇文章当中主要跟大家介绍以下几点前缀、中缀和后缀表达式。如何将中缀表达式转化成后缀表......
  • How to Change Reset Retrieve the WebLogic Server Administrator Password on WLS 1
    TochangetheAdministratorpasswordonWLS10.3.6orearlier,performthefollowingstepsdependingonyoursituation:IFYOUKNOWCURRENTPASSWORDStartthe......