数据结构之Trie

Trie

什么是Trie

我们知道一个线性表的顺序查找的时间复杂度为O(n);二分搜索树的查找为O(log n),它们都和数据结构中的元素个数相关。关于线性表和二分搜索树的时间复杂度分析有需要的可以查看 Set集合和BinarySearchTree的时间复杂度分析

本文介绍的Trie字典树(主要用于存储字符串)查找速度主要和它的元素(字符串)的长度相关[O(w)]。

Trie字典树主要用于存储字符串,Trie 的每个 Node 保存一个字符。用链表来描述的话,就是一个字符串就是一个链表。每个Node都保存了它的所有子节点。

我们日常中使用的通讯录就是一个例子。

如果有N个条目,使用树结构查询的时间复杂度是O(logn)

而如果用Trie查询每个条目的时间复杂度与字段中一共有多少条目无关!时间复杂度为O(W)

W为查询单词的长度!

每个节点有26个指向下个节点的指针

Class Node{
        char c;
        Node next[ 26];
}

在Trie中叶子节点并不一定是单词的结尾,像平底锅的英文是pan而熊猫是panda我们不能只根据叶子节点来区分单词的末尾,所以我们需要一个变量来存储当前节点是否是某个单词的结尾。

class Node{
    boolean isWord;
    Map next;
}

特点

  • 根节点不包含字符,除根节点外每一个节点都只包含一个字符
  • 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串
  • 每个节点的所有子节点包含的字符都不相同

Trie字典树的新增

public class Trie {
        private class Node{
            public boolean isWord;
            public TreeMap next;
            public Node() {
                this(false);
            }
            public Node(boolean isWord){
                this.isWord = isWord;
                next = new TreeMap<>();
            }
        }
        private Node root;
        private int size;
        public Trie(){
            root = new Node();
            size = 0;
        }
        //获得Trie中存储单词的数量
        public int getSize(){
            return size;
        }
        //向Trie中添加一个新的单词word
        public void add(String word){
            Node cur = root;
            for (int i = 0; i < word.length(); i++) {
                char c = word.charAt(i);
                if(cur.next.get(c) == null){
                    cur.next.put(c,new Node());
                }
                cur = cur.next.get(c);
            }
            if(!cur.isWord){
                cur.isWord = true;
                size ++;
            }
        }
}

Trie字典树的查询

    //查询单词word是否在Trie中
    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);
        }
        return cur.isWord;
    }
    //查询是否在Trie中有单词以prefix为前缀
    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;
    }

你可能感兴趣的:(java,数据结构)