字典树

字典树

1.1 基本数据结构

数据结构大都离不开数组链表。他们是计算机中最基本的数据机构,基本全部的数据机构均可以有这两种数据机构来实现。java

而链表是一种特殊的树,树更是一种特殊的图。node

极客时间 数学专栏的做者的一段话,一直以为很受用:算法

其实计算机到了最后仍是搞数学,咱们要作的就是如何将问题应用到数学在到编程上去。编程

数学思想到编程的实现大都分为三步走数组

  • 把问题转化为数学中的模型
  • 用数据结构与算法来刻画数学模型
  • 落实编码

1.2 字典树

1.2.1 什么是字典树?数据结构

字典树也能够叫作前缀树,其实就是将不少单词组成的一种数据机构。一般都是树形结构的全部叫作字典树。ui

以下图所示:this

跟节点一般都是空,不一样的单词组成一条条的通路,造成了一个树状结构。编码

字典树有两种实现方式链表数组spa

由于字典树的二维关系是很是稀疏很是动态的,因此采用链表来实现字典树。

具体的代码注释以下:

static class TreeNode{

        /** * 节点的数据void */
        private char data;

        /** * 子节点 */
        private Map<Character,TreeNode>  sons = null;

        /** * 节点的解释 */
        private String explanation = null;

        /** * 节点的前缀字符串 */
        private String prefix = null;


        public TreeNode(char data, String explanation, String prefix) {
            this.data = data;
            this.sons = new HashMap<>(16);
            this.explanation = explanation;
            this.prefix = prefix;
        }
    }
复制代码

1.2.2 字典树的操做

字典树有两种

由于字典树的二维关系是很是稀疏很是动态的,

字典树的操做有两个

  • 构建字典树(Dynamic)

    public static void buildPrefixTree(String word){
            if(StringUtils.isEmpty(word)) {
                return;
            }
    
            TreeNode findNode = headNode;
            String prefix = "";
            String explanation = null;
    
            for(int i=0;i<word.length();i++){
                char c = word.charAt(i);
                Map<Character, TreeNode> sons = findNode.sons;
                if(sons.containsKey(c)){
                    findNode = sons.get(c);
                }else{
                    if(i == word.length()-1){
                        explanation = prefix + c;
                    }
                    TreeNode sonNode = new TreeNode(c,explanation,prefix);
                    sons.put(c,sonNode);
                    findNode = sonNode;
                }
                prefix += c;
            }
        }
    复制代码
  • 查询字典

/** * 在PrefixTree中查找 单词 * @param word * @return */
    public static TreeNode findWrod(String word){

        if(StringUtils.isEmpty(word)) {
            return null;
        }
        TreeNode findNode = headNode;

        for(int i=0;i<word.length();i++){
            char c = word.charAt(i);
            Map<Character, TreeNode> sons = findNode.sons;

            if( sons.size()!=0 && sons.containsKey(c)){
                findNode = sons.get(c);
            }else{
                return null;
            }
        }

        if(StringUtils.isEmpty(findNode.explanation)){
            return null;
        }

        return findNode;
    }
复制代码
  • 遍历字典树中的全部单词

    /** * 使用栈便利全部的单词 */
        public static void dfsByStack(){
            Stack<TreeNode>  stack = new Stack<>();
            stack.push(headNode);
            while(stack.size()>0){
                TreeNode node = stack.pop();
                if(!StringUtils.isEmpty(node.explanation)){
                    System.out.println(node.explanation);
                }
                Map<Character, TreeNode> sons = node.sons;
                sons.forEach((sonKey,sonValue)->{
                    stack.push(sonValue);
                });
            }
        }
    复制代码

字典树的这三种操做其实均可以用递归来实现,可是最后一种的效率是明显优于递归的,由于减小了大量的中间变量的建立,利用了栈模拟了递归调用。

相关文章
相关标签/搜索