十二、轻松理解字典树Trie

324 阅读1分钟

字典树(前缀树)Trie

目标:

  • 认识Trie
  • Trie的实现
  • 查询
    • 前缀查询
  • 模式匹配
  • Trie和字符串的映射

1.1 认识Trie

查询每个条目的时间复杂度,和字典中一共有多少条目无关。时间复杂度为O(w),w为查询单词的长度。

字典:如果有n个条目,使用树结构,查询的时间复杂度为O(logn),如果有100万个条目(2^20^),logn大约是20。

Trie的结构图:

image-20200921171652724

将整个字符串以字母为单位进行拆开,从根节点开始一直到叶子节点,去遍历,每遍历到一个叶子节点,就形成一个单词。

每个节点有若干指向下个节点的指针。

有些单词是某些单词的前缀,所以每一个node需要一个标识:是否是单词的结尾。

1.2 Trie的实现

boolean isWord;

Map<Character, Node> next;

  • 添加元素:

    添加一个字符串,然后拆为一个个字符,将这些字符装填进树中,作为节点。

    // 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字典树的查询
    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;
      }