今天看啥  ›  专栏  ›  弑晓风

由简入繁--Trie树实战

弑晓风  · 掘金  ·  · 2019-03-22 15:27

文章预览

阅读 34

由简入繁--Trie树实战

You only get one shot, do not miss your chance to blow. 
你只有一发子弹,不要错过引爆全场的机会。

引言

trie树又称“字典树”。关键词提示功能在日常生活中非常常用,通常只需要输出前缀,它就会给出相应的提示。呢具体是怎么实现的呢?本文主要分享了基于trie树的一个简易的搜索提示以及trie树常用的应用场景。所有源码均已上传至github:链接

ps:Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起。

模拟搜索关键词提示功能

本次实现其实也可以改造一下,将用户习惯(输入内容)存成一颗trie树

以how,hi,her,hello,so,see为例

声明一个tire类

这里偷了个小懒,整了一个内部类。

    public class TrieNode {
        /**
         * 字符
         */
        public char data;
        /**
         * 子节点
         */
        TrieNode[] children;
        /**
         * 标识
         */
        boolean isEndingChar;

        TrieNode(char data) {
            children = new TrieNode[26];
            isEndingChar = false;
            this.data = data;
        }
    }复制代码

初始化

通常根节点是不存储任何信息的,起一个占位符的作用

 /**
     * 根节点
     */
    private TrieNode root;

    /**
     * 预制单词数量
     */
    private int count;

    /**
     * 提示词列表
     */
    private List<String> list;

    /**
     * 输入值
     */
    private String pattern;

    /**
     * 存储一个无意义的字符
     */
    private TrieTree() {
        root = new TrieNode('/');
        count = 0;
        list = new ArrayList<>();
    }复制代码

插入

    private void insert(char[] txt) {
        TrieNode p = root;
        for (char c : txt) {
            //当前字符的ASCII码 - 'a'的 ASCII码
            int index = c - 'a';
            if (null == p.children[index]) {
                TrieNode node = new TrieNode(c);
                p.children[index] = node;
            }
            p = p.children[index];
        }
        ++count;
        p.isEndingChar = true;
    }复制代码

查询

    private boolean contains(String pattern) {
        char[] patChars = pattern.toCharArray();
        TrieNode p = root;
        for (char patChar : patChars) {
            int index = patChar - 'a';
            if (null == p.children[index])
                return false;
            p = p.children[index];
        }
        return p.isEndingChar;
    }复制代码

模糊提示匹配

    private void match() {
        char[] patChars = pattern.toCharArray();
        TrieNode p = root;
        for (char patChar : patChars) {
            int index = patChar - 'a';
            if (null == p.children[index])
                return;
            p = p.children[index];
        }
        //开始遍历 p,将所有匹配的字符加入strs
        traversal(p, "");
    }复制代码

递归遍历节点

    private void traversal(TrieNode trieNode, String str) {
        if (null != trieNode) {
            str += trieNode.data;
            if (trieNode.isEndingChar) {
                String curStr = pattern.length() == 1 ? 
		str : pattern + str.substring(pattern.length() - 1);
                if (!list.contains(curStr))
                    list.add(curStr);
                return;
            }
            for (int i = 0; i < trieNode.children.length; i++) {
                traversal(trieNode.children[i], str);
            }
        }
    }复制代码

测试代码

人为构造一个tire树

ps:这里的存储会导致树很高,比如 l l o,其实可以合成llo,也就是缩点优化。这里暂时不实现了。

    private void initTries() {
//        how,hi,her,hello,so,see
//                   /
//              h         s
//           e  i  o    o   e
//         l         w        e
//      l
//   o
        char[] how = "how".toCharArray();
        insert(how);
        char[] hi = "hi".toCharArray();
        insert(hi);
        char[] her = "her".toCharArray();
        insert(her);
        char[] hello = "hello".toCharArray();
        insert(hello);
        char[] so = "so".toCharArray();
        insert(so);
        char[] see = "see".toCharArray();
        insert(see);
    }复制代码

测试代码

    public static void main(String[] args) {
        TrieTree trieTree = new TrieTree();
        trieTree.initTries();
        String str = "hello";
        boolean res = trieTree.contains(str);
        System.out.println("trie树是否包含" + str + "返回结果:" + res);

        trieTree.pattern = "h";
        trieTree.match();
        System.out.println("单字符模糊匹配 " + trieTree.pattern + ":");
        trieTree.printAll();

        trieTree.list.clear();
        trieTree.pattern = "he";
        trieTree.match();
        System.out.println("多字符模糊匹配 " + trieTree.pattern + ":");
        trieTree.printAll();
    }复制代码

测试结果


trie树实战

未完待续...

end


您的点赞和关注是对我最大的支持,谢谢!


………………………………

原文地址:访问原文地址
快照地址: 访问文章快照
总结与预览地址:访问总结与预览