Trie(字典树,前缀树)

Trie(字典树,前缀树)

字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
三个基本性质:
+ 根节点不包含字符,除根节点外每一个节点都只包含一个字符;
+ 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
+ 每个节点的所有子节点包含的字符都不相同。

具体代码实现

package Trie;

import java.util.TreeMap;

/**
 * @ Description: Trie 前缀树 字典树 经常用于字符串的处理
 * @ Date: Created in 10:36 22/07/2018
 * @ Author: Anthony_Duan
 */
public class Trie {

    private class Node {
        //标识该节点是否是一个单词的结尾
        public boolean isWord;
        //使用映射来存储26 个英文字母的对应的节点
        public TreeMap<Character, Node> next;

        public Node(boolean isWord) {
            this.isWord = isWord;
            next = new TreeMap<>();
        }

        //默认标识节点不是一个单词的结尾
        public Node() {
            this(false);
        }
    }


    private Node root;
    private int size;

    public Trie() {
        root = new Node();
        size = 0;
    }

    //获取Trie中存储的单词的数量
    public int getSize() {
        return size;
    }

    /**
     * 向Trie中添加一个新的单词
     *
     * @param word
     */
    public void add(String word) {

        Node cur = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            //如果在当前节点的next中没有找到下一个字母的映射 就添加一个新的映射进去
            if (cur.next.get(c) == null) {
                cur.next.put(c, new Node());
            }
            cur = cur.next.get(c);
        }

        /**
         * 这里是一个容易忽略的错误
         * 当单词中的每一个单词都添加完后
         * 需要查看最后一个字母的isWord字段是否为true 如果为true 表示这个单词已经被标识过了
         * 如果为false 表示这个单词还没有被标识过
         */
        if (!cur.isWord) {
            cur.isWord = true;
            size++;
        }
    }

    public boolean contains(String word) {
        Node cur = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (cur.next.get(c) == null) {
                return false;
            }
            cur = cur.next.get(c);
        }
        /**
         * 这里需要注意的是 不能直接返回true
         * 因为即便所有的单词的字母都被搜索到了
         * 但是如果最后一个字母的isWord没有被标识为true
         * 则该单词就没有作为一个单词存储进去,而是另一个单词的前缀
         * 所以这里返回最后一个单词的isWord字段
         */
        return cur.isWord;
    }

    public boolean isPrefix(String prefix) {
        Node cur = root;
        for (int i = 0; i < prefix.length(); i++) {
            char c = prefix.charAt(i);
            if (cur.next.get(c) == null) {
                return false;
            }
            cur = cur.next.get(c);
        }
        return true;
    }

}

猜你喜欢

转载自blog.csdn.net/xiaoduan_/article/details/81214921