当前位置: 首页 > news >正文

字典树收集(初步读写锁实现线程安全,待续)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

edcd35d594835f3e45538015f59da8f1069.jpg

将500W个单词放进一个数据结构进行存储,然后进行快速比对,判断一个单词是不是这个500W单词之中的;来了一个单词前缀,给出500w个单词中有多少个单词是该前缀.

1、这个需求首先需要设计好数据结构,要求快速判断一个单词是否在这500W之中,挨个遍历肯定不是好办法,即便你把他们放在一个数组或者链表里,用多线程分段查找,最好是几次查找就可以知道结果。

我们把所有单词的前缀作为上层,剩下的字符逐级加入到树的下层结构中,并记录树的上层节点的子节点数。这样我们只要判断新单词跟树的上层节点的前缀比对,那么其他不匹配的节点就无需继续遍历,只需要在该节点往下查找后续的字符比对,他的时间复杂度可能就很低了,只需要几次比对就能判断出是否包含该新单词。整个数据结构可以书写如下。

public class DictionaryTree {

    // 字典树的节点
    private class Node {
        // 是否是单词
        private boolean isWord;
        // 单词计数
        private int count;
        // 字串
        private String str;
        // 子节点
        private Map<String, Node> childs;
        // 父节点
        private Node parent;

        public Node() {
            childs = new HashMap<String, Node>();
        }

        public Node(boolean isWord, int count, String str) {
            this();
            this.isWord = isWord;
            this.count = count;
            this.str = str;
        }

        public void addChild(String key, Node node) {
            childs.put(key, node);
            node.parent = this;
        }

        public void removeChild(String key) {
            childs.remove(key);
        }

        public String toString() {
            return "str : " + str + ", isWord : " + isWord + ", count : " + count;
        }
    }

    // 字典树根节点
    private Node root;

    public DictionaryTree() {
        // 初始化root
        root = new Node();
    }

    // 添加字串
    private void addStr(String word, Node node) {

        // 计数
        node.count++;

        String str = node.str;
        if (null != str) {

            // 寻找公共前缀
            String commonPrefix = "";
            for (int i = 0; i < word.length(); i++) {
                if (str.length() > i && word.charAt(i) == str.charAt(i)) {
                    commonPrefix += word.charAt(i);
                } else {
                    break;
                }
            }

            // 找到公共前缀
            if (commonPrefix.length() > 0) {
                if (commonPrefix.length() == str.length() && commonPrefix.length() == word.length()) {
                    // 与之前的词重复
                } else if (commonPrefix.length() == str.length() && commonPrefix.length() < word.length()) {
                    // 剩余的串
                    String wordLeft = word.substring(commonPrefix.length());
                    // 剩余的串去子节点中继续找
                    searchChild(wordLeft, node);
                } else if (commonPrefix.length() < str.length()) {
                    // 节点裂变
                    Node splitNode = new Node(true, node.count, commonPrefix);
                    // 处理裂变节点的父关系
                    splitNode.parent = node.parent;
                    splitNode.parent.addChild(commonPrefix, splitNode);
                    node.parent.removeChild(node.str);
                    node.count--;
                    // 节点裂变后的剩余字串
                    String strLeft = str.substring(commonPrefix.length());
                    node.str = strLeft;
                    splitNode.addChild(strLeft, node);
                    // 单词裂变后的剩余字串
                    if (commonPrefix.length() < word.length()) {
                        splitNode.isWord = false;
                        String wordLeft = word.substring(commonPrefix.length());
                        Node leftNode = new Node(true, 1, wordLeft);
                        splitNode.addChild(wordLeft, leftNode);
                    }
                }
            } else {
                // 没有共同前缀,直接添加节点
                Node newNode = new Node(true, 1, word);
                node.addChild(word, newNode);
            }
        } else {
            // 根结点
            if (node.childs.size() > 0) {
                searchChild(word, node);
            } else {
                Node newNode = new Node(true, 1, word);
                node.addChild(word, newNode);
            }
        }
    }

    // 在子节点中添加字串
    public void searchChild(String wordLeft, Node node) {
        boolean isFind = false;
        if (node.childs.size() > 0) {
            // 遍历孩子
            for (String childKey : node.childs.keySet()) {
                Node childNode = node.childs.get(childKey);
                // 首字母相同,则在该子节点继续添加字串
                if (wordLeft.charAt(0) == childNode.str.charAt(0)) {
                    isFind = true;
                    addStr(wordLeft, childNode);
                    break;
                }
            }
        }
        // 没有首字母相同的孩子,则将其变为子节点
        if (!isFind) {
            Node newNode = new Node(true, 1, wordLeft);
            node.addChild(wordLeft, newNode);
        }
    }

    // 添加单词
    public void add(String word) {
        addStr(word, root);
    }

    // 在节点中查找字串
    private boolean findStr(String word, Node node) {
        boolean isMatch = true;
        String wordLeft = word;
        String str = node.str;
        if (null != str) {
            // 字串与单词不匹配
            if (word.indexOf(str) != 0) {
                isMatch = false;
            } else {
                // 匹配,则计算剩余单词(从匹配的后一位到最后一位)
                wordLeft = word.substring(str.length());
            }
        }
        // 如果匹配
        if (isMatch) {
            // 如果还有剩余单词长度
            if (wordLeft.length() > 0) {
                if (node.childs.size() > 0) {
                    // 遍历孩子继续找
                    for (String key : node.childs.keySet()) {
                        Node childNode = node.childs.get(key);
                        //递归
                        boolean isChildFind = findStr(wordLeft, childNode);
                        if (isChildFind) {
                            return true;
                        }
                    }
                }else {
                    //如果没有子节点了,返回false
                    return false;
                }
            } else {
                // 没有剩余单词长度,说明已经匹配完毕,直接返回节点是否为单词,匹配到即便符合前缀,也不能算单词
                return node.isWord;
            }
        }
        return false;
    }

    // 查找单词
    public boolean find(String word) {
        return findStr(word, root);
    }

    // 统计子节点字串单词数
    private int countChildStr(String prefix, Node node) {
        // 遍历孩子
        for (String key : node.childs.keySet()) {
            Node childNode = node.childs.get(key);
            // 匹配子节点
            int childCount = countStr(prefix, childNode);
            if (childCount != 0) {
                return childCount;
            }
        }
        return 0;
    }

    // 统计字串单词数
    private int countStr(String prefix, Node node) {
        String str = node.str;
        // 非根结点
        if (null != str) {
            // 前缀与字串不匹配
            if (prefix.indexOf(str) != 0 && str.indexOf(prefix) != 0) {
                return 0;
                // 前缀匹配字串,且前缀较短
            } else if (str.indexOf(prefix) == 0) {
                // 找到目标节点,返回单词数
                return node.count;
                // 前缀匹配字串,且字串较短
            } else if (prefix.indexOf(str) == 0) {
                // 剩余字串继续匹配子节点
                String prefixLeft = prefix.substring(str.length());
                if (prefixLeft.length() > 0) {
                    return countChildStr(prefixLeft, node);
                }
            }
        } else {
            // 根结点,直接找其子孙
            return countChildStr(prefix, node);
        }
        return 0;
    }

    // 统计前缀单词数
    public int count(String prefix) {
        // 处理特殊情况
        if (null == prefix || prefix.trim().isEmpty()) {
            return root.count;
        }
        // 从根结点往下匹配
        return countStr(prefix, root);
    }

    // 打印节点
    private void printNode(Node node, int layer) {
        // 层级递进
        for (int i = 0; i < layer; i++) {
            System.out.print("    ");
        }
        // 打印
        System.out.println(node);
        // 递归打印子节点
        for (String str : node.childs.keySet()) {
            Node child = node.childs.get(str);
            printNode(child, layer + 1);
        }
    }

    // 打印字典树
    public void print() {
        printNode(root, 0);
    }
}

我们可以先看findStr()方法,主要是递归查找,也就是递归进去几个节点的事情,就OK了.

// 在节点中查找字串
private boolean findStr(String word, Node node) {
    boolean isMatch = true;
    String wordLeft = word;
    String str = node.str;
    if (null != str) {
        // 字串与单词不匹配
        if (word.indexOf(str) != 0) {
            isMatch = false;
        } else {
            // 匹配,则计算剩余单词(从匹配的后一位到最后一位)
            wordLeft = word.substring(str.length());
        }
    }
    // 如果匹配
    if (isMatch) {
        // 如果还有剩余单词长度
        if (wordLeft.length() > 0) {
            if (node.childs.size() > 0) {
                // 遍历孩子继续找
                for (String key : node.childs.keySet()) {
                    Node childNode = node.childs.get(key);
                    //递归
                    boolean isChildFind = findStr(wordLeft, childNode);
                    if (isChildFind) {
                        return true;
                    }
                }
            }else {
                //如果没有子节点了,返回false
                return false;
            }
        } else {
            // 没有剩余单词长度,说明已经匹配完毕,直接返回节点是否为单词,匹配到即便符合前缀,也不能算单词
            return node.isWord;
        }
    }
    return false;
}

// 查找单词
public boolean find(String word) {
    return findStr(word, root);
}

第二个需求,来了一个单词前缀,给出500w个单词中有多少个单词是该前缀.

我们来看一下countStr()和countChildStr()两个方法的互相调用,其实就是我只要找到完全匹配子节点的数量就可以得到结果.他的时间复杂度也是非常的低.不需要一个个的去到叶节点去累加,因为上层节点已经有他的全部单词节点节点的数量.(上层节点也可能是一个单词,并非只是叶节点)

// 统计子节点字串单词数
private int countChildStr(String prefix, Node node) {
    // 遍历孩子
    for (String key : node.childs.keySet()) {
        Node childNode = node.childs.get(key);
        // 匹配子节点
        int childCount = countStr(prefix, childNode);
        if (childCount != 0) {
            return childCount;
        }
    }
    return 0;
}

// 统计字串单词数
private int countStr(String prefix, Node node) {
    String str = node.str;
    // 非根结点
    if (null != str) {
        // 前缀与字串不匹配
        if (prefix.indexOf(str) != 0 && str.indexOf(prefix) != 0) {
            return 0;
            // 前缀匹配字串,且前缀较短
        } else if (str.indexOf(prefix) == 0) {
            // 找到目标节点,返回单词数
            return node.count;
            // 前缀匹配字串,且字串较短
        } else if (prefix.indexOf(str) == 0) {
            // 剩余字串继续匹配子节点
            String prefixLeft = prefix.substring(str.length());
            if (prefixLeft.length() > 0) {
                return countChildStr(prefixLeft, node);
            }
        }
    } else {
        // 根结点,直接找其子孙
        return countChildStr(prefix, node);
    }
    return 0;
}

// 统计前缀单词数
public int count(String prefix) {
    // 处理特殊情况
    if (null == prefix || prefix.trim().isEmpty()) {
        return root.count;
    }
    // 从根结点往下匹配
    return countStr(prefix, root);
}

添加单词也是非常有意思的,来看这么几个方法.当新增加的单词跟已存在的节点单词有相同的前缀时,就要分裂出一个新的前缀节点,并且把该节点本身以及新增加的单词的后续的字符变成两个下一级节点,如果没有就要新增加一个全新的节点.如果已经有前缀可以匹配了,就要匹配下一层的前缀,其他同之前.

// 添加字串
private void addStr(String word, Node node) {

    // 计数
    node.count++;

    String str = node.str;
    if (null != str) {

        // 寻找公共前缀
        String commonPrefix = "";
        for (int i = 0; i < word.length(); i++) {
            if (str.length() > i && word.charAt(i) == str.charAt(i)) {
                commonPrefix += word.charAt(i);
            } else {
                break;
            }
        }

        // 找到公共前缀
        if (commonPrefix.length() > 0) {
            if (commonPrefix.length() == str.length() && commonPrefix.length() == word.length()) {
                // 与之前的词重复
            } else if (commonPrefix.length() == str.length() && commonPrefix.length() < word.length()) {
                // 剩余的串
                String wordLeft = word.substring(commonPrefix.length());
                // 剩余的串去子节点中继续找
                searchChild(wordLeft, node);
            } else if (commonPrefix.length() < str.length()) {
                // 节点裂变
                Node splitNode = new Node(true, node.count, commonPrefix);
                // 处理裂变节点的父关系
                splitNode.parent = node.parent;
                splitNode.parent.addChild(commonPrefix, splitNode);
                node.parent.removeChild(node.str);
                node.count--;
                // 节点裂变后的剩余字串
                String strLeft = str.substring(commonPrefix.length());
                node.str = strLeft;
                splitNode.addChild(strLeft, node);
                // 单词裂变后的剩余字串
                if (commonPrefix.length() < word.length()) {
                    splitNode.isWord = false;
                    String wordLeft = word.substring(commonPrefix.length());
                    Node leftNode = new Node(true, 1, wordLeft);
                    splitNode.addChild(wordLeft, leftNode);
                }
            }
        } else {
            // 没有共同前缀,直接添加节点
            Node newNode = new Node(true, 1, word);
            node.addChild(word, newNode);
        }
    } else {
        // 根结点
        if (node.childs.size() > 0) {
            searchChild(word, node);
        } else {
            Node newNode = new Node(true, 1, word);
            node.addChild(word, newNode);
        }
    }
}

// 在子节点中添加字串
public void searchChild(String wordLeft, Node node) {
    boolean isFind = false;
    if (node.childs.size() > 0) {
        // 遍历孩子
        for (String childKey : node.childs.keySet()) {
            Node childNode = node.childs.get(childKey);
            // 首字母相同,则在该子节点继续添加字串
            if (wordLeft.charAt(0) == childNode.str.charAt(0)) {
                isFind = true;
                addStr(wordLeft, childNode);
                break;
            }
        }
    }
    // 没有首字母相同的孩子,则将其变为子节点
    if (!isFind) {
        Node newNode = new Node(true, 1, wordLeft);
        node.addChild(wordLeft, newNode);
    }
}

// 添加单词
public void add(String word) {
    addStr(word, root);
}
public void addChild(String key, Node node) {
    childs.put(key, node);
    node.parent = this;
}

然后我们来一个main()方法进行测试,当然没有加500W个单词那么多,但结果是一样,有兴趣你可以加500W个单词进去

public static void main(String[] args) {

    DictionaryTree dt = new DictionaryTree();

    dt.add("interest");
    dt.add("interesting");
    dt.add("interested");
    dt.add("inside");
    dt.add("insert");
    dt.add("apple");
    dt.add("inter");
    dt.add("interesting");
    dt.add("aha");
    dt.add("fuck");
    dt.add("finish");
    dt.add("fish");

    dt.print();

    boolean isFind = dt.find("a");
    System.out.println("find a : " + isFind);

    isFind = dt.find("aha");
    System.out.println("find aha : " + isFind);

    int count = dt.count("inter");
    System.out.println("count prefix inter : " + count);

}

运行结果:

str : null, isWord : false, count : 12
    str : a, isWord : false, count : 2
        str : ha, isWord : true, count : 1
        str : pple, isWord : true, count : 1
    str : in, isWord : false, count : 7
        str : ter, isWord : true, count : 5
            str : est, isWord : true, count : 4
                str : ing, isWord : true, count : 2
                str : ed, isWord : true, count : 1
        str : s, isWord : false, count : 2
            str : ert, isWord : true, count : 1
            str : ide, isWord : true, count : 1
    str : f, isWord : false, count : 3
        str : i, isWord : false, count : 2
            str : nish, isWord : true, count : 1
            str : sh, isWord : true, count : 1
        str : uck, isWord : true, count : 1
find a : false
find aha : true
count prefix inter : 5

实现线程安全性(读写锁实现,初步)

package com.guanjian;

/**
 * Created by Administrator on 2018/10/21.
 */
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class DictionaryTree {
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    private Lock readLock = reentrantReadWriteLock.readLock();
    private Lock writeLock = reentrantReadWriteLock.writeLock();
    // 字典树的节点
    private class Node {
        // 是否是单词
        private boolean isWord;
        // 单词计数
        private int count;
        // 字串
        private String str;
        // 子节点
        private Map<String, Node> childs;
        // 父节点
        private Node parent;

        public Node() {
            childs = new HashMap<String, Node>();
        }

        public Node(boolean isWord, int count, String str) {
            this();
            this.isWord = isWord;
            this.count = count;
            this.str = str;
        }

        public void addChild(String key, Node node) {
            childs.put(key, node);
            node.parent = this;
        }

        public void removeChild(String key) {
            childs.remove(key);
        }

        public String toString() {
            return "str : " + str + ", isWord : " + isWord + ", count : " + count;
        }
    }

    // 字典树根节点
    private Node root;

    public DictionaryTree() {
        // 初始化root
        root = new Node();
    }

    // 添加字串
    private void addStr(String word, Node node) {

        // 计数
        node.count++;

        String str = node.str;
        if (null != str) {

            // 寻找公共前缀
            String commonPrefix = "";
            for (int i = 0; i < word.length(); i++) {
                if (str.length() > i && word.charAt(i) == str.charAt(i)) {
                    commonPrefix += word.charAt(i);
                } else {
                    break;
                }
            }

            // 找到公共前缀
            if (commonPrefix.length() > 0) {
                if (commonPrefix.length() == str.length() && commonPrefix.length() == word.length()) {
                    // 与之前的词重复
                } else if (commonPrefix.length() == str.length() && commonPrefix.length() < word.length()) {
                    // 剩余的串
                    String wordLeft = word.substring(commonPrefix.length());
                    // 剩余的串去子节点中继续找
                    searchChild(wordLeft, node);
                } else if (commonPrefix.length() < str.length()) {
                    // 节点裂变
                    Node splitNode = new Node(true, node.count, commonPrefix);
                    // 处理裂变节点的父关系
                    splitNode.parent = node.parent;
                    splitNode.parent.addChild(commonPrefix, splitNode);
                    node.parent.removeChild(node.str);
                    node.count--;
                    // 节点裂变后的剩余字串
                    String strLeft = str.substring(commonPrefix.length());
                    node.str = strLeft;
                    splitNode.addChild(strLeft, node);
                    // 单词裂变后的剩余字串
                    if (commonPrefix.length() < word.length()) {
                        splitNode.isWord = false;
                        String wordLeft = word.substring(commonPrefix.length());
                        Node leftNode = new Node(true, 1, wordLeft);
                        splitNode.addChild(wordLeft, leftNode);
                    }
                }
            } else {
                // 没有共同前缀,直接添加节点
                Node newNode = new Node(true, 1, word);
                node.addChild(word, newNode);
            }
        } else {
            // 根结点
            if (node.childs.size() > 0) {
                searchChild(word, node);
            } else {
                Node newNode = new Node(true, 1, word);
                node.addChild(word, newNode);
            }
        }
    }

    // 在子节点中添加字串
    public void searchChild(String wordLeft, Node node) {
        boolean isFind = false;
        if (node.childs.size() > 0) {
            // 遍历孩子
            for (String childKey : node.childs.keySet()) {
                Node childNode = node.childs.get(childKey);
                // 首字母相同,则在该子节点继续添加字串
                if (wordLeft.charAt(0) == childNode.str.charAt(0)) {
                    isFind = true;
                    addStr(wordLeft, childNode);
                    break;
                }
            }
        }
        // 没有首字母相同的孩子,则将其变为子节点
        if (!isFind) {
            Node newNode = new Node(true, 1, wordLeft);
            node.addChild(wordLeft, newNode);
        }
    }

    // 添加单词
    public void add(String word) {
        try {
            writeLock.lock();
            addStr(word, root);
        }finally {
            writeLock.unlock();
        }

    }

    // 在节点中查找字串
    private boolean findStr(String word, Node node) {
        boolean isMatch = true;
        String wordLeft = word;
        String str = node.str;
        if (null != str) {
            // 字串与单词不匹配
            if (word.indexOf(str) != 0) {
                isMatch = false;
            } else {
                // 匹配,则计算剩余单词(从匹配的后一位到最后一位)
                wordLeft = word.substring(str.length());
            }
        }
        // 如果匹配
        if (isMatch) {
            // 如果还有剩余单词长度
            if (wordLeft.length() > 0) {
                if (node.childs.size() > 0) {
                    // 遍历孩子继续找
                    for (String key : node.childs.keySet()) {
                        Node childNode = node.childs.get(key);
                        //递归
                        boolean isChildFind = findStr(wordLeft, childNode);
                        if (isChildFind) {
                            return true;
                        }
                    }
                }else {
                    //如果没有子节点了,返回false
                    return false;
                }
            } else {
                // 没有剩余单词长度,说明已经匹配完毕,直接返回节点是否为单词,匹配到即便符合前缀,也不能算单词
                return node.isWord;
            }
        }
        return false;
    }

    // 查找单词
    public boolean find(String word) {
        try {
            readLock.lock();
            return findStr(word, root);
        }finally {
            readLock.unlock();
        }

    }

    // 统计子节点字串单词数
    private int countChildStr(String prefix, Node node) {
        // 遍历孩子
        for (String key : node.childs.keySet()) {
            Node childNode = node.childs.get(key);
            // 匹配子节点
            int childCount = countStr(prefix, childNode);
            if (childCount != 0) {
                return childCount;
            }
        }
        return 0;
    }

    // 统计字串单词数
    private int countStr(String prefix, Node node) {
        String str = node.str;
        // 非根结点
        if (null != str) {
            // 前缀与字串不匹配
            if (prefix.indexOf(str) != 0 && str.indexOf(prefix) != 0) {
                return 0;
                // 前缀匹配字串,且前缀较短
            } else if (str.indexOf(prefix) == 0) {
                // 找到目标节点,返回单词数
                return node.count;
                // 前缀匹配字串,且字串较短
            } else if (prefix.indexOf(str) == 0) {
                // 剩余字串继续匹配子节点
                String prefixLeft = prefix.substring(str.length());
                if (prefixLeft.length() > 0) {
                    return countChildStr(prefixLeft, node);
                }
            }
        } else {
            // 根结点,直接找其子孙
            return countChildStr(prefix, node);
        }
        return 0;
    }

    // 统计前缀单词数
    public int count(String prefix) {
        // 处理特殊情况
        try {
            readLock.lock();
            if (null == prefix || prefix.trim().isEmpty()) {
                return root.count;
            }
            // 从根结点往下匹配
            return countStr(prefix, root);
        }finally {
            readLock.unlock();
        }

    }

    // 打印节点
    private void printNode(Node node, int layer) {
        // 层级递进
        for (int i = 0; i < layer; i++) {
            System.out.print("    ");
        }
        // 打印
        System.out.println(node);
        // 递归打印子节点
        for (String str : node.childs.keySet()) {
            Node child = node.childs.get(str);
            printNode(child, layer + 1);
        }
    }

    // 打印字典树
    public void print() {
        try {
            readLock.lock();
            printNode(root, 0);
        }finally {
            readLock.unlock();
        }

    }
    public static String getRandomString(int length) {
        Random random=new Random();
        StringBuffer sb=new StringBuffer();
        //循环length次
        for(int i = 0; i < length; i++){
            //产生0-2个随机数,既与a-z,A-Z,0-9三种可能
//            int number=random.nextInt(3);
            int number = 1;
            long result = 0L;
            switch(number){
                //如果number产生的是数字0;
                case 0:
                    //产生A-Z的ASCII码
                    result = Math.round(Math.random()*25+65);
                    //将ASCII码转换成字符
                    sb.append(String.valueOf((char)result));
                    break;
                case 1:
                    //产生a-z的ASCII码
                    result=Math.round(Math.random()*25+97);
                    sb.append(String.valueOf((char)result));
                    break;
                case 2:
                    //产生0-9的数字
                    sb.append(String.valueOf
                            (new Random().nextInt(10)));
                    break;
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) throws InterruptedException {

        DictionaryTree dt = new DictionaryTree();
        CountDownLatch latch = new CountDownLatch(500);
        Runnable task = new Runnable() {
            @Override
            public void run() {
                dt.add(getRandomString(10));
                latch.countDown();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
        for (int i = 0;i < 500;i++) {
            es.submit(task);
        }
        latch.await();
//        dt.add("interest");
//        dt.add("interesting");
//        dt.add("interested");
//        dt.add("inside");
//        dt.add("insert");
//        dt.add("apple");
//        dt.add("inter");
//        dt.add("interesting");
//        dt.add("aha");
//        dt.add("fuck");
//        dt.add("finish");
//        dt.add("fish");

        dt.print();

        boolean isFind = dt.find("a");
        System.out.println("find a : " + isFind);

        isFind = dt.find("aha");
        System.out.println("find aha : " + isFind);

        int count = dt.count("inter");
        System.out.println("count prefix inter : " + count);
        es.shutdown();
    }
}

运行结果:

str : null, isWord : false, count : 500
    str : a, isWord : false, count : 13
        str : aynktxfyv, isWord : true, count : 1
        str : qsmxpqlhe, isWord : true, count : 1
        str : jvtrvhvlp, isWord : true, count : 1
        str : dfakhoyje, isWord : true, count : 1
        str : myclcdtmm, isWord : true, count : 1
        str : cdpenahjw, isWord : true, count : 1
        str : fvxoyszdo, isWord : true, count : 1
        str : giobhpfeu, isWord : true, count : 1
        str : i, isWord : false, count : 2
            str : xaakwfbn, isWord : true, count : 1
            str : goeeixla, isWord : true, count : 1
        str : vthbspcbw, isWord : true, count : 1
        str : stmrgrokg, isWord : true, count : 1
        str : tstmujfvm, isWord : true, count : 1
    str : b, isWord : false, count : 18
        str : ahckiaakm, isWord : true, count : 1
        str : ibkxlklnp, isWord : true, count : 1
        str : syclxybky, isWord : true, count : 1
        str : qustarhze, isWord : true, count : 1
        str : u, isWord : false, count : 3
            str : ohlifgck, isWord : true, count : 1
            str : lopecahh, isWord : true, count : 1
            str : khclgcyd, isWord : true, count : 1
        str : ktybpnhgj, isWord : true, count : 1
        str : w, isWord : false, count : 2
            str : xogivfbc, isWord : true, count : 1
            str : jjdmtiel, isWord : true, count : 1
        str : x, isWord : false, count : 3
            str : qimqqitp, isWord : true, count : 1
            str : giwcjqvv, isWord : true, count : 1
            str : tpmunncg, isWord : true, count : 1
        str : npixbfxgq, isWord : true, count : 1
        str : j, isWord : false, count : 2
            str : ktvhgytz, isWord : true, count : 1
            str : jcxrihjw, isWord : true, count : 1
        str : lcsrejxcj, isWord : true, count : 1
        str : ezxizwqnx, isWord : true, count : 1
    str : c, isWord : false, count : 23
        str : bvbvpncmi, isWord : true, count : 1
        str : a, isWord : false, count : 2
            str : ohbsqhyv, isWord : true, count : 1
            str : pgrhuhvj, isWord : true, count : 1
        str : fqdmrupqi, isWord : true, count : 1
        str : xzkqsrfnl, isWord : true, count : 1
        str : qnjvgwlqm, isWord : true, count : 1
        str : ylxqipkii, isWord : true, count : 1
        str : vxmxaogax, isWord : true, count : 1
        str : o, isWord : false, count : 4
            str : adtoabkk, isWord : true, count : 1
            str : evgmvyox, isWord : true, count : 1
            str : obippxob, isWord : true, count : 1
            str : wmkmtjln, isWord : true, count : 1
        str : myxiuxpse, isWord : true, count : 1
        str : jwyypaxpj, isWord : true, count : 1
        str : t, isWord : false, count : 2
            str : rqbhnnre, isWord : true, count : 1
            str : gncvbqsf, isWord : true, count : 1
        str : rjfghlovy, isWord : true, count : 1
        str : u, isWord : false, count : 2
            str : vnzghtcf, isWord : true, count : 1
            str : ygicbibt, isWord : true, count : 1
        str : w, isWord : false, count : 2
            str : ebxnwiba, isWord : true, count : 1
            str : jhnsjjfu, isWord : true, count : 1
        str : z, isWord : false, count : 2
            str : gcxchyhj, isWord : true, count : 1
            str : fmgotnym, isWord : true, count : 1
    str : d, isWord : false, count : 20
        str : b, isWord : false, count : 2
            str : isoprvlr, isWord : true, count : 1
            str : kwwchnhv, isWord : true, count : 1
        str : g, isWord : false, count : 2
            str : ubhtbbdb, isWord : true, count : 1
            str : thnfdskg, isWord : true, count : 1
        str : thgudyfqy, isWord : true, count : 1
        str : nxfvflgyf, isWord : true, count : 1
        str : i, isWord : false, count : 2
            str : hhfflsmk, isWord : true, count : 1
            str : botkntno, isWord : true, count : 1
        str : k, isWord : false, count : 2
            str : wwetdhxd, isWord : true, count : 1
            str : kmksjtvo, isWord : true, count : 1
        str : ahfxtzfwy, isWord : true, count : 1
        str : ennqllhgu, isWord : true, count : 1
        str : ukxjneotd, isWord : true, count : 1
        str : o, isWord : false, count : 2
            str : pfwgcijy, isWord : true, count : 1
            str : buchntfb, isWord : true, count : 1
        str : cxdouqbfr, isWord : true, count : 1
        str : wlfjthkap, isWord : true, count : 1
        str : xyxywylpf, isWord : true, count : 1
        str : hzgvpnafs, isWord : true, count : 1
        str : zjkpjzttb, isWord : true, count : 1
    str : e, isWord : false, count : 20
        str : b, isWord : false, count : 2
            str : uctinobl, isWord : true, count : 1
            str : bbqjgdup, isWord : true, count : 1
        str : fbwjnhbej, isWord : true, count : 1
        str : i, isWord : false, count : 2
            str : rvpojxdf, isWord : true, count : 1
            str : gsydkjyn, isWord : true, count : 1
        str : j, isWord : false, count : 2
            str : usflntug, isWord : true, count : 1
            str : fkqfyhyb, isWord : true, count : 1
        str : omdkokrvr, isWord : true, count : 1
        str : qhvvhucmb, isWord : true, count : 1
        str : drqpbvhlx, isWord : true, count : 1
        str : vvtrgqsdy, isWord : true, count : 1
        str : lwqlxzpwg, isWord : true, count : 1
        str : sifbolcpi, isWord : true, count : 1
        str : tragbqswl, isWord : true, count : 1
        str : awfsciltt, isWord : true, count : 1
        str : w, isWord : false, count : 3
            str : icvimuaz, isWord : true, count : 1
            str : nxluecgg, isWord : true, count : 1
            str : tdqioyrz, isWord : true, count : 1
        str : hgnbncypo, isWord : true, count : 1
        str : untsoedek, isWord : true, count : 1
    str : f, isWord : false, count : 19
        str : ffzeobwsr, isWord : true, count : 1
        str : s, isWord : false, count : 3
            str : dclynbdk, isWord : true, count : 1
            str : gmpwfjrj, isWord : true, count : 1
            str : ewuqujtw, isWord : true, count : 1
        str : mfrlmqmfr, isWord : true, count : 1
        str : d, isWord : false, count : 6
            str : nqrngqrb, isWord : true, count : 1
            str : gfyoguqf, isWord : true, count : 1
            str : esyjhfzm, isWord : true, count : 1
            str : pejvnpqc, isWord : true, count : 1
            str : qkgwhdjm, isWord : true, count : 1
            str : mmyrwluh, isWord : true, count : 1
        str : bkfagjiri, isWord : true, count : 1
        str : psplkjufd, isWord : true, count : 1
        str : h, isWord : false, count : 2
            str : wutdthld, isWord : true, count : 1
            str : dwpjrjbw, isWord : true, count : 1
        str : k, isWord : false, count : 2
            str : mhgksicu, isWord : true, count : 1
            str : wcaxwdnq, isWord : true, count : 1
        str : nxuyasjgx, isWord : true, count : 1
        str : gewomfbwu, isWord : true, count : 1
    str : g, isWord : false, count : 23
        str : i, isWord : false, count : 2
            str : zjjsubas, isWord : true, count : 1
            str : rbcgawsc, isWord : true, count : 1
        str : geyfehanp, isWord : true, count : 1
        str : j, isWord : false, count : 2
            str : gvitwrvd, isWord : true, count : 1
            str : amfrozmf, isWord : true, count : 1
        str : ssqfbuwbv, isWord : true, count : 1
        str : djyvjlrsi, isWord : true, count : 1
        str : qvvpdvicc, isWord : true, count : 1
        str : lugpxdvej, isWord : true, count : 1
        str : fuaxzbyhx, isWord : true, count : 1
        str : o, isWord : false, count : 2
            str : pjpwkbzh, isWord : true, count : 1
            str : ncrwrpho, isWord : true, count : 1
        str : prardfgdn, isWord : true, count : 1
        str : vcnplwbie, isWord : true, count : 1
        str : u, isWord : false, count : 2
            str : rzmconay, isWord : true, count : 1
            str : esvrfjjv, isWord : true, count : 1
        str : kjhyxrrwn, isWord : true, count : 1
        str : y, isWord : false, count : 2
            str : tidbmpvw, isWord : true, count : 1
            str : bpbgagsp, isWord : true, count : 1
        str : z, isWord : false, count : 3
            str : aeirvyss, isWord : true, count : 1
            str : hhkvdvtj, isWord : true, count : 1
            str : fvkniezk, isWord : true, count : 1
        str : xsqsdhnks, isWord : true, count : 1
    str : h, isWord : false, count : 22
        str : a, isWord : false, count : 2
            str : ghnrudof, isWord : true, count : 1
            str : ckkpnlwh, isWord : true, count : 1
        str : c, isWord : false, count : 2
            str : bgcieeix, isWord : true, count : 1
            str : uinorkfm, isWord : true, count : 1
        str : d, isWord : false, count : 2
            str : cpsughmq, isWord : true, count : 1
            str : kmftctvq, isWord : true, count : 1
        str : g, isWord : false, count : 2
            str : begltzfb, isWord : true, count : 1
            str : cmrqgjsj, isWord : true, count : 1
        str : j, isWord : false, count : 2
            str : wcbqscvq, isWord : true, count : 1
            str : hknrmaop, isWord : true, count : 1
        str : nxpdvqwcp, isWord : true, count : 1
        str : l, isWord : false, count : 2
            str : qsxomrcy, isWord : true, count : 1
            str : fnjeyout, isWord : true, count : 1
        str : xkvtoggor, isWord : true, count : 1
        str : hehvmiobd, isWord : true, count : 1
        str : s, isWord : false, count : 2
            str : ljnwwidx, isWord : true, count : 1
            str : nygyfssr, isWord : true, count : 1
        str : v, isWord : false, count : 2
            str : jytrtose, isWord : true, count : 1
            str : encidcbk, isWord : true, count : 1
        str : yxwenwbjo, isWord : true, count : 1
        str : ie, isWord : false, count : 2
            str : ndcsikr, isWord : true, count : 1
            str : pkczlwa, isWord : true, count : 1
    str : i, isWord : false, count : 21
        str : zxtdgcsug, isWord : true, count : 1
        str : kgdvcgjwa, isWord : true, count : 1
        str : goimnjuxe, isWord : true, count : 1
        str : d, isWord : false, count : 2
            str : vsnbmygo, isWord : true, count : 1
            str : nellduoq, isWord : true, count : 1
        str : vsmnbrczt, isWord : true, count : 1
        str : ibeuypnkt, isWord : true, count : 1
        str : l, isWord : false, count : 2
            str : lskozfen, isWord : true, count : 1
            str : edguybhq, isWord : true, count : 1
        str : ouflycyoe, isWord : true, count : 1
        str : ftoyvxhao, isWord : true, count : 1
        str : eistonoes, isWord : true, count : 1
        str : q, isWord : false, count : 2
            str : wdhyditq, isWord : true, count : 1
            str : fbfrhzmr, isWord : true, count : 1
        str : wkmrtnvjg, isWord : true, count : 1
        str : s, isWord : false, count : 4
            str : finqjpic, isWord : true, count : 1
            str : akdlvdvh, isWord : true, count : 1
            str : kvnqexnm, isWord : true, count : 1
            str : lshsmdxv, isWord : true, count : 1
        str : bplhteiyc, isWord : true, count : 1
        str : cetvqlbod, isWord : true, count : 1
    str : j, isWord : false, count : 24
        str : yqxlnrimk, isWord : true, count : 1
        str : dbrgxlhdg, isWord : true, count : 1
        str : mtsasvlyp, isWord : true, count : 1
        str : c, isWord : false, count : 2
            str : nhowgxzt, isWord : true, count : 1
            str : jacfwjsi, isWord : true, count : 1
        str : uwuhwcaxp, isWord : true, count : 1
        str : g, isWord : false, count : 3
            str : ijmffwnq, isWord : true, count : 1
            str : ceafgjft, isWord : true, count : 1
            str : xvxtqffh, isWord : true, count : 1
        str : j, isWord : false, count : 2
            str : datglbgb, isWord : true, count : 1
            str : psofjwbu, isWord : true, count : 1
        str : xwnlgjyln, isWord : true, count : 1
        str : o, isWord : false, count : 3
            str : uicqpgny, isWord : true, count : 1
            str : kfrruuhh, isWord : true, count : 1
            str : ajdfqsft, isWord : true, count : 1
        str : sfsdflxgq, isWord : true, count : 1
        str : igfkxtwfm, isWord : true, count : 1
        str : ztxjbfluo, isWord : true, count : 1
        str : q, isWord : false, count : 2
            str : oovyrzen, isWord : true, count : 1
            str : nwrsfsjb, isWord : true, count : 1
        str : rufxxbisb, isWord : true, count : 1
        str : v, isWord : false, count : 2
            str : pxkvluon, isWord : true, count : 1
            str : vcyiuooi, isWord : true, count : 1
        str : fogdyyarp, isWord : true, count : 1
    str : k, isWord : false, count : 20
        str : uiyhichvr, isWord : true, count : 1
        str : mekbpgkkh, isWord : true, count : 1
        str : i, isWord : false, count : 2
            str : dbahjpps, isWord : true, count : 1
            str : slgbmcoy, isWord : true, count : 1
        str : recqutazs, isWord : true, count : 1
        str : zabvtxmbx, isWord : true, count : 1
        str : p, isWord : false, count : 3
            str : mgzbigsj, isWord : true, count : 1
            str : rsnsneku, isWord : true, count : 1
            str : nysqhncd, isWord : true, count : 1
        str : yegghtvoe, isWord : true, count : 1
        str : ebqtzmlsw, isWord : true, count : 1
        str : cw, isWord : false, count : 2
            str : yppoojo, isWord : true, count : 1
            str : qqiepin, isWord : true, count : 1
        str : lnpiibvry, isWord : true, count : 1
        str : qkldejdeg, isWord : true, count : 1
        str : v, isWord : false, count : 2
            str : hcakcrip, isWord : true, count : 1
            str : pyocmnxr, isWord : true, count : 1
        str : aqsvubqrh, isWord : true, count : 1
        str : fwhlgothm, isWord : true, count : 1
        str : gtkunybjp, isWord : true, count : 1
    str : l, isWord : false, count : 16
        str : tykwoeyma, isWord : true, count : 1
        str : foenehshj, isWord : true, count : 1
        str : ykodlbvhk, isWord : true, count : 1
        str : dpojvwruz, isWord : true, count : 1
        str : pnjuamwih, isWord : true, count : 1
        str : wfovkcpea, isWord : true, count : 1
        str : uqbxvhcej, isWord : true, count : 1
        str : h, isWord : false, count : 3
            str : q, isWord : false, count : 2
                str : xcmsyjw, isWord : true, count : 1
                str : gtybdgz, isWord : true, count : 1
            str : cwdhfljl, isWord : true, count : 1
        str : asirzknwb, isWord : true, count : 1
        str : j, isWord : false, count : 2
            str : weavcfwf, isWord : true, count : 1
            str : axobpyzy, isWord : true, count : 1
        str : bssldvnod, isWord : true, count : 1
        str : n, isWord : false, count : 2
            str : yigypswa, isWord : true, count : 1
            str : voinhset, isWord : true, count : 1
    str : m, isWord : false, count : 20
        str : a, isWord : false, count : 2
            str : jzxvsbuq, isWord : true, count : 1
            str : bnsdwxmw, isWord : true, count : 1
        str : b, isWord : false, count : 2
            str : evpbddpa, isWord : true, count : 1
            str : ynqeqzgc, isWord : true, count : 1
        str : zbdvbvcnl, isWord : true, count : 1
        str : d, isWord : false, count : 2
            str : ylwyxlkc, isWord : true, count : 1
            str : idwxbtei, isWord : true, count : 1
        str : omtbqtxei, isWord : true, count : 1
        str : sdqgwgnjo, isWord : true, count : 1
        str : wlmkkzwqb, isWord : true, count : 1
        str : qdxpxsowd, isWord : true, count : 1
        str : p, isWord : false, count : 2
            str : namqmvte, isWord : true, count : 1
            str : ukhcsuow, isWord : true, count : 1
        str : yclsmbgvb, isWord : true, count : 1
        str : u, isWord : false, count : 2
            str : juovneoh, isWord : true, count : 1
            str : vmttfvos, isWord : true, count : 1
        str : v, isWord : false, count : 2
            str : teprigjs, isWord : true, count : 1
            str : qylrswml, isWord : true, count : 1
        str : x, isWord : false, count : 2
            str : fiuthpwm, isWord : true, count : 1
            str : jjgmgxjy, isWord : true, count : 1
    str : n, isWord : false, count : 18
        str : wxdkvgywg, isWord : true, count : 1
        str : c, isWord : false, count : 2
            str : eebdkkkd, isWord : true, count : 1
            str : cqdlojgh, isWord : true, count : 1
        str : tudnypngd, isWord : true, count : 1
        str : d, isWord : false, count : 2
            str : qjvbeqoy, isWord : true, count : 1
            str : gviclxjq, isWord : true, count : 1
        str : vpwcaekjx, isWord : true, count : 1
        str : f, isWord : false, count : 2
            str : yfwyxsru, isWord : true, count : 1
            str : vvtmjnlq, isWord : true, count : 1
        str : olnrywqvo, isWord : true, count : 1
        str : iosebaodr, isWord : true, count : 1
        str : uwmoitczp, isWord : true, count : 1
        str : xrsbofbtt, isWord : true, count : 1
        str : ngvnhrbfs, isWord : true, count : 1
        str : y, isWord : false, count : 3
            str : vtqvwssx, isWord : true, count : 1
            str : lplphgmh, isWord : true, count : 1
            str : tcotbygo, isWord : true, count : 1
        str : jdxvxxptx, isWord : true, count : 1
    str : o, isWord : false, count : 14
        str : kvhhlbdab, isWord : true, count : 1
        str : bumffivtn, isWord : true, count : 1
        str : plnebqeao, isWord : true, count : 1
        str : mpwjixmmt, isWord : true, count : 1
        str : tpsqklver, isWord : true, count : 1
        str : u, isWord : false, count : 2
            str : qpxxhiyj, isWord : true, count : 1
            str : lkbfgrjq, isWord : true, count : 1
        str : dkoejecvg, isWord : true, count : 1
        str : nyobqxjks, isWord : true, count : 1
        str : fcjhwdlcg, isWord : true, count : 1
        str : rqdudbfee, isWord : true, count : 1
        str : o, isWord : false, count : 3
            str : rcysotjt, isWord : true, count : 1
            str : sbxohfbd, isWord : true, count : 1
            str : pofgixiv, isWord : true, count : 1
    str : p, isWord : false, count : 27
        str : nqdtikyvx, isWord : true, count : 1
        str : b, isWord : false, count : 2
            str : kpkqcpql, isWord : true, count : 1
            str : fznlible, isWord : true, count : 1
        str : c, isWord : false, count : 2
            str : mhterbxy, isWord : true, count : 1
            str : debpoecx, isWord : true, count : 1
        str : ustwlwqjd, isWord : true, count : 1
        str : jowdmdbvt, isWord : true, count : 1
        str : k, isWord : false, count : 4
            str : efrfnyce, isWord : true, count : 1
            str : bkpoopsa, isWord : true, count : 1
            str : dqyuumto, isWord : true, count : 1
            str : ieubnydl, isWord : true, count : 1
        str : ixrtmuhnb, isWord : true, count : 1
        str : o, isWord : false, count : 2
            str : ykygvgcy, isWord : true, count : 1
            str : noqmgruu, isWord : true, count : 1
        str : q, isWord : false, count : 2
            str : xurbngrr, isWord : true, count : 1
            str : zrmcwtqs, isWord : true, count : 1
        str : hxlkusrvz, isWord : true, count : 1
        str : mbspmgiux, isWord : true, count : 1
        str : s, isWord : false, count : 2
            str : cmklndaf, isWord : true, count : 1
            str : tqjxoxve, isWord : true, count : 1
        str : t, isWord : false, count : 2
            str : zfmitvyj, isWord : true, count : 1
            str : ildpdzmx, isWord : true, count : 1
        str : v, isWord : false, count : 2
            str : hhscedqv, isWord : true, count : 1
            str : lbtgvjcs, isWord : true, count : 1
        str : y, isWord : false, count : 2
            str : pxtrjgqy, isWord : true, count : 1
            str : jqkotwhe, isWord : true, count : 1
        str : pizddnvmh, isWord : true, count : 1
    str : q, isWord : false, count : 15
        str : byhsnctqd, isWord : true, count : 1
        str : jhnvdbkdi, isWord : true, count : 1
        str : t, isWord : false, count : 2
            str : zvnemtiq, isWord : true, count : 1
            str : ebrcpsqe, isWord : true, count : 1
        str : u, isWord : false, count : 4
            str : npscqpop, isWord : true, count : 1
            str : ccmypnca, isWord : true, count : 1
            str : movdxpdf, isWord : true, count : 1
            str : bhinjrcu, isWord : true, count : 1
        str : fvmiivshy, isWord : true, count : 1
        str : gyficrern, isWord : true, count : 1
        str : nrnljmnsl, isWord : true, count : 1
        str : pjllpuili, isWord : true, count : 1
        str : wvvlevgqd, isWord : true, count : 1
        str : o, isWord : false, count : 2
            str : jpvlsbsu, isWord : true, count : 1
            str : rudrudqj, isWord : true, count : 1
    str : r, isWord : false, count : 20
        str : ilubscsym, isWord : true, count : 1
        str : r, isWord : false, count : 3
            str : neyqpuhc, isWord : true, count : 1
            str : jvlyynuu, isWord : true, count : 1
            str : sxucdpiq, isWord : true, count : 1
        str : s, isWord : false, count : 2
            str : jmyigesh, isWord : true, count : 1
            str : vcwubtml, isWord : true, count : 1
        str : oxllpefko, isWord : true, count : 1
        str : bcvwsogdd, isWord : true, count : 1
        str : pcvotvpuq, isWord : true, count : 1
        str : f, isWord : false, count : 2
            str : vibimlag, isWord : true, count : 1
            str : evrpfumm, isWord : true, count : 1
        str : egsvvlovf, isWord : true, count : 1
        str : w, isWord : false, count : 4
            str : odihhdvq, isWord : true, count : 1
            str : binhvwac, isWord : true, count : 1
            str : dgtxcylv, isWord : true, count : 1
            str : haegudbo, isWord : true, count : 1
        str : xkqnixyfi, isWord : true, count : 1
        str : k, isWord : false, count : 3
            str : fyckhlee, isWord : true, count : 1
            str : cdjtcjrq, isWord : true, count : 1
            str : dhyejwsg, isWord : true, count : 1
    str : s, isWord : false, count : 25
        str : kcwlvxxuc, isWord : true, count : 1
        str : b, isWord : false, count : 2
            str : blidfzih, isWord : true, count : 1
            str : vgdddnmm, isWord : true, count : 1
        str : c, isWord : false, count : 4
            str : cxgtfkdo, isWord : true, count : 1
            str : h, isWord : false, count : 2
                str : wuvcunq, isWord : true, count : 1
                str : inaflrp, isWord : true, count : 1
            str : tussjbav, isWord : true, count : 1
        str : e, isWord : false, count : 2
            str : cvvorcwz, isWord : true, count : 1
            str : amlthaxk, isWord : true, count : 1
        str : ldkxnmril, isWord : true, count : 1
        str : gqlwnjmlf, isWord : true, count : 1
        str : vqkhldfdw, isWord : true, count : 1
        str : mewetpryj, isWord : true, count : 1
        str : q, isWord : false, count : 4
            str : oltgrppw, isWord : true, count : 1
            str : c, isWord : false, count : 2
                str : pkgljhj, isWord : true, count : 1
                str : ctfidpz, isWord : true, count : 1
            str : whxisjbg, isWord : true, count : 1
        str : oduwvijdn, isWord : true, count : 1
        str : xhdxhnspi, isWord : true, count : 1
        str : s, isWord : false, count : 2
            str : ohsvwemq, isWord : true, count : 1
            str : tfitotfu, isWord : true, count : 1
        str : rrdthzbqq, isWord : true, count : 1
        str : y, isWord : false, count : 2
            str : iubthgjs, isWord : true, count : 1
            str : ejccuiwh, isWord : true, count : 1
        str : jflguhwgh, isWord : true, count : 1
    str : t, isWord : false, count : 14
        str : dibehwpvb, isWord : true, count : 1
        str : c, isWord : false, count : 2
            str : hzmoycnt, isWord : true, count : 1
            str : rdbppojv, isWord : true, count : 1
        str : yygjpogbz, isWord : true, count : 1
        str : zuusmshca, isWord : true, count : 1
        str : ieuqncuud, isWord : true, count : 1
        str : rwsvnhcmw, isWord : true, count : 1
        str : otghtuvqo, isWord : true, count : 1
        str : ugasrmtuy, isWord : true, count : 1
        str : j, isWord : false, count : 2
            str : nxdcehvh, isWord : true, count : 1
            str : rpmyapuw, isWord : true, count : 1
        str : lkoswttyr, isWord : true, count : 1
        str : m, isWord : false, count : 2
            str : lmdbsqml, isWord : true, count : 1
            str : iqrbwxfx, isWord : true, count : 1
    str : u, isWord : false, count : 20
        str : xbhssncfj, isWord : true, count : 1
        str : uwpofcpoc, isWord : true, count : 1
        str : d, isWord : false, count : 2
            str : jufrmoxn, isWord : true, count : 1
            str : yxlsgsku, isWord : true, count : 1
        str : qvkkobbwj, isWord : true, count : 1
        str : m, isWord : false, count : 2
            str : yclcwpve, isWord : true, count : 1
            str : lfvbnafq, isWord : true, count : 1
        str : cisxawvgp, isWord : true, count : 1
        str : n, isWord : false, count : 2
            str : qomvggve, isWord : true, count : 1
            str : eoqcvkjc, isWord : true, count : 1
        str : jlopfvfyn, isWord : true, count : 1
        str : s, isWord : false, count : 3
            str : iultquie, isWord : true, count : 1
            str : glsdcszb, isWord : true, count : 1
            str : hvtacxck, isWord : true, count : 1
        str : w, isWord : false, count : 2
            str : opldtdkw, isWord : true, count : 1
            str : fmuoxxdy, isWord : true, count : 1
        str : vpcadsief, isWord : true, count : 1
        str : tsrhbsivm, isWord : true, count : 1
        str : aybxoetvn, isWord : true, count : 1
        str : fcvrmdfje, isWord : true, count : 1
    str : v, isWord : false, count : 21
        str : a, isWord : false, count : 2
            str : rprkekdt, isWord : true, count : 1
            str : qvcteorp, isWord : true, count : 1
        str : gtqhbewsb, isWord : true, count : 1
        str : b, isWord : false, count : 2
            str : bbvdfabi, isWord : true, count : 1
            str : wybqnobb, isWord : true, count : 1
        str : lswdvufbu, isWord : true, count : 1
        str : d, isWord : false, count : 2
            str : cgvkugmv, isWord : true, count : 1
            str : hdyvqvso, isWord : true, count : 1
        str : e, isWord : false, count : 2
            str : xjhewjfn, isWord : true, count : 1
            str : ubusbnck, isWord : true, count : 1
        str : jrkyuqfhy, isWord : true, count : 1
        str : uxwlhbcdm, isWord : true, count : 1
        str : v, isWord : false, count : 2
            str : lwpqrkxk, isWord : true, count : 1
            str : qstkbtvg, isWord : true, count : 1
        str : fbkrymshl, isWord : true, count : 1
        str : cuvyidufi, isWord : true, count : 1
        str : z, isWord : false, count : 2
            str : insawsph, isWord : true, count : 1
            str : disumgpv, isWord : true, count : 1
        str : oeilidftj, isWord : true, count : 1
        str : pqvqhmwxk, isWord : true, count : 1
        str : hbplpplns, isWord : true, count : 1
    str : w, isWord : false, count : 19
        str : c, isWord : false, count : 2
            str : htlmjxdb, isWord : true, count : 1
            str : kcytuqno, isWord : true, count : 1
        str : f, isWord : false, count : 2
            str : bfqitldc, isWord : true, count : 1
            str : mghqdaok, isWord : true, count : 1
        str : g, isWord : false, count : 2
            str : phytwsfg, isWord : true, count : 1
            str : gpclxbve, isWord : true, count : 1
        str : h, isWord : false, count : 2
            str : snichuuh, isWord : true, count : 1
            str : ajqnnvnb, isWord : true, count : 1
        str : bmdkoeteg, isWord : true, count : 1
        str : m, isWord : false, count : 2
            str : ssnhnquu, isWord : true, count : 1
            str : yxuymjci, isWord : true, count : 1
        str : ltwfkipuz, isWord : true, count : 1
        str : q, isWord : false, count : 2
            str : qmaofhux, isWord : true, count : 1
            str : izjglqwe, isWord : true, count : 1
        str : dkuttvjfq, isWord : true, count : 1
        str : vktomypri, isWord : true, count : 1
        str : rpbpttgcv, isWord : true, count : 1
        str : ksrdoqsgq, isWord : true, count : 1
        str : phqeihumc, isWord : true, count : 1
    str : x, isWord : false, count : 23
        str : rkfwgdrtg, isWord : true, count : 1
        str : nbkiqhfiw, isWord : true, count : 1
        str : c, isWord : false, count : 2
            str : qoxcdbqn, isWord : true, count : 1
            str : fknahuuc, isWord : true, count : 1
        str : gbxmsbtga, isWord : true, count : 1
        str : joaommefq, isWord : true, count : 1
        str : yroekddqh, isWord : true, count : 1
        str : uihdqbzxy, isWord : true, count : 1
        str : o, isWord : false, count : 2
            str : uremdykm, isWord : true, count : 1
            str : hnbikpte, isWord : true, count : 1
        str : q, isWord : false, count : 2
            str : emgreolm, isWord : true, count : 1
            str : ssxplvcl, isWord : true, count : 1
        str : s, isWord : false, count : 2
            str : ffnphust, isWord : true, count : 1
            str : aiijhflt, isWord : true, count : 1
        str : hwfhcwjzy, isWord : true, count : 1
        str : t, isWord : false, count : 2
            str : fpeymosg, isWord : true, count : 1
            st

主要应用场景:

3b7e558078b961ea4c8d3166238b1be94c5.jpg

搜索提示框,不过这些功能现在其实大部分被搜索引擎(如elasticsearch等)用的已经很成熟了,这篇文章也算是一个对树使用的非常好的例子.

转载于:https://my.oschina.net/u/3768341/blog/2250382

相关文章:

  • c#开发移动APP-Xamarin入门剖析
  • Pytest 生成Report
  • 小白创建一个spring boot项目
  • spring-boot项目中如何集成使用thymeleaf
  • Module build failed: Error: No PostCSS Config found
  • 面试疑云
  • 报表实时刷新显示时间
  • Linux SVN服务器的搭建配置及分支的创建与合并
  • 线程的定时器Timer
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • PhpStudy的安装及使用教程
  • [PHP] 算法-顺时针打印矩阵的PHP实现
  • Java集合-HashMap扰动函数
  • Django-jet自定义菜单
  • 解决org.apache.hadoop.hbase.MasterNotRunningException
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • 【刷算法】从上往下打印二叉树
  • Centos6.8 使用rpm安装mysql5.7
  • const let
  • git 常用命令
  • iOS编译提示和导航提示
  • Java 23种设计模式 之单例模式 7种实现方式
  • JAVA_NIO系列——Channel和Buffer详解
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JavaScript设计模式系列一:工厂模式
  • Javascript设计模式学习之Observer(观察者)模式
  • js中的正则表达式入门
  • Node + FFmpeg 实现Canvas动画导出视频
  • PHP 7 修改了什么呢 -- 2
  • React as a UI Runtime(五、列表)
  • Tornado学习笔记(1)
  • Vue 动态创建 component
  • vue的全局变量和全局拦截请求器
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 关于for循环的简单归纳
  • 力扣(LeetCode)21
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 怎么把视频里的音乐提取出来
  • 中文输入法与React文本输入框的问题与解决方案
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (6)STL算法之转换
  • (SpringBoot)第七章:SpringBoot日志文件
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (十八)三元表达式和列表解析
  • (十一)图像的罗伯特梯度锐化
  • (算法)N皇后问题
  • (算法)Travel Information Center
  • (算法二)滑动窗口