zoukankan      html  css  js  c++  java
  • 数据结构 -- Trie字典树

    简介

      字典树:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。

      优点利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

      性质:   1.  根节点不包含字符,除根节点外每一个节点都只包含一个字符;

          2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;

          3.  每个节点的所有子节点包含的字符都不相同。

      应用场景:用于统计,排序保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。

          

    代码 实现

     本文使用链表来实现Trie字典树,字符串的每个字符作为一个Node节点,Node主要有两部分组成:

    1. 是否是单词 (boolean isWord)
    2. 节点所有的子节点,用map来保存 (Map next)

    添加

    public void add(String word) {
        Node current = root;
        char[] cs = word.toCharArray();
        for (char c : cs) {
            Node next = current.next.get(c);
            if (next == null) {
                //一个字符对应一个Node节点
                current.next.put(c, new Node());
            }
            current = current.next.get(c);
        }
        //current就是word的最后一个字符的Node
        
        //如果当前的node已经是一个word,则不需要添加
        if (!current.isWord) {
            size++;
            current.isWord = true;
        }
    }

    查找

      Trie查找操作就比较简单了,遍历带查找的字符串的字符,如果每个节点都存在,并且待查找字符串的最后一个字符对应的Node的 isWord 属性为 true ,则表示该单词存在

    public boolean contains(String word) {
        Node current = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            Node node = current.next.get(c);
            if (node == null) {
                return false;
            }
            current = node;
        }
        //current就是word的最后一个字符的Node
        return current.isWord;
    }

    前缀查询

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

    删除

    Trie的删除操作就稍微复杂一些,主要分为以下3种情况:

      1. 如果单词是另一个单词的前缀

        如果待删除的单词是另一个单词的前缀,只需要把该单词的最后一个节点的 isWord 的改成false,比如Trie中存在 panda 和 pan 这两个单词,删除 pan ,只需要把字符 n 对应的节点的 isWord 改成 false 即可。

          

      2. 如果单词的所有字母的都无分支,删除整个单词。

        如果单词的所有字母的都没有多个分支(也就是说该单词所有的字符对应的Node都只有一个子节点),则删除整个单词。      

          

      3. 如果单词的除了最后一个字母,其他的字母有多个分支

        

     public boolean remove(String word){
            Node multiChildNode = null;
            int multiChildNodeIndex = -1;
            Node current = root;
            for (int i = 0; i < word.length(); i++) {
                Node child = current.next.get(word.charAt(i));
                //如果Trie中没有这个单词
                if (child == null) {
                    return false;
                }
                //当前节点的子节点大于1个
                if (child.next.size() > 1) {
                    multiChildNodeIndex = i;
                    multiChildNode = child;
                }
                current = child;
            }
            //如果单词后面还有子节点
            if (current.next.size() > 0) {
                if (current.isWord) {
                    current.isWord = false;
                    size--;
                    return true;
                }
                //不存在该单词,该单词只是前缀
                return false;
            }
            //如果单词的所有字母的都没有多个分支,删除整个单词
            if (multiChildNodeIndex == -1) {
                root.next.remove(word.charAt(0));
                size--;
                return true;
            }
            //如果单词的除了最后一个字母,其他的字母有分支
            if (multiChildNodeIndex != word.length() - 1) {
                multiChildNode.next.remove(word.charAt(multiChildNodeIndex + 1));
                size--;
                return true;
            }
            return false;
        }

    Trie查询效率非常高,但是对空间的消耗还是挺大的,这也是典型的空间换时间。

    可以使用 压缩字典树(Compressed Trie) ,但是维护相对来说复杂一些。

    如果我们不止存储英文单词,还有其他特殊字符,那么维护子节点的集合可能会更多。

    可以对Trie字典树做些限制,比如每个节点只能有3个子节点,左边的节点是小于父节点的,中间的节点是等于父节点的,右边的子节点是大于父节点的,这就是三分搜索Trie字典树(Ternary Search Trie)。

    参考:https://blog.csdn.net/johnny901114/article/details/80711441

  • 相关阅读:
    字符串替换
    字符串查找
    字符串比较
    字节与字符串相互转换
    1365. How Many Numbers Are Smaller Than the Current Number
    1486. XOR Operation in an Array
    1431. Kids With the Greatest Number of Candies
    1470. Shuffle the Array
    1480. Running Sum of 1d Array
    【STM32H7教程】第56章 STM32H7的DMA2D应用之刷色块,位图和Alpha混合
  • 原文地址:https://www.cnblogs.com/FondWang/p/11896425.html
Copyright © 2011-2022 走看看