字典树(单词查找树)详解

文章目录

  • 前言
  • 什么是字典树
    • 性质
  • 代码详解
    • 属性 & 构造器
    • insert 插入
    • searchPrefix 搜索前缀
  • 完整代码:

前言

当你在搜索条输入字符时,搜索引擎会根据你所输入的字符进行提示,这就是字典树的引用,他根据公共前缀来进行提示,可以减少不必要的比较。

本文将从代码层面让你彻底了解字典树,以最简单的字典树开始,以达到扩展的目的。

什么是字典树

字典树又被称为单词查找树或者前缀树,Trie,是一种树形结构。典型应用是用于统计,排序和保存大量的字符串。

它的优点是:利用字符串的公共前缀来减少查询时间,减少字符串的比较,查询效率比哈希树高。

性质

  • 根节点不包含字符,除根结点外每一个结点都只包含一个字符。
  • 从根节点到某一结点,路劲上经过的字符连接起来,为该点对应的字符串。(通过一个标志,来判断此字符是否为某字符串的结尾)
  • 每个结点所有的子结点包含的字符都不相同。

代码详解

最简单的字典树,可以自行添加其他属性,

比如:当前结点所代表的字符,或者有没有子结点(这些都不是必需的

属性 & 构造器

属性

 Trie[] child;//保存下一个字符
 boolean isEnd;//如果是字符串的结尾 则为tree

构造器

 public Trie() {
        child = new Trie[26];//总共有26个单词
        isEnd = false;//根节点
    }

child:用一个数组来保存孩子结点。字符的数量为26,所以数组的大小也为26。如果某个位置为 null 则代表没有这个字符。
isEnd:用来判断这个字符是不是字符串的结尾,如果是true,将其前面的路径连接起来就代表该字符串

insert 插入

public void insert(String word) {
        //首先拿到根tire
        Trie cur =this;
        //循环插入
        for (char ch : word.toCharArray()){
            //计算当前字符在数组中的位置
            int index = ch -'a';
            //保存此字符 如果这和索引所在的位置不为null 就说名有字符
           if (cur.child[index] ==null) {
               cur.child[index] = new Trie();
           }

            cur = cur.child[index];
        }
        //退出循环时 cur指向字符串的末尾 设为true
        cur.isEnd = true;
    }

思路:

  1. 首先拿到根结点
  2. 计算字符在数组中的位置
  3. 循环插入字符
  4. 给末尾的字符,设置标志位为true

searchPrefix 搜索前缀

public Trie searchPrefix(String word){
        //拿到根trie
        Trie cur = this;
        //遍历
        for (char ch : word.toCharArray()){
            //计算位置
            int index = ch-'a';
            //如果字符所代表的位置为空 则返回null
            if (cur.child[index]==null){
                return null;
            }

            cur = cur.child[index];
        }
        //返回最后一个字符所代表的tire
        return cur;
    }

思路:

  1. 拿到根节点
  2. 遍历字符,计算每个字符在数组中的位置
    会有两种情况
    为null,说明不存在此字符直接返回null
    不为null,则遍历下一个结点
  3. 当遍历到最后一个结点时返回该节点
  • 很明显如果能够返回结点,就说明该字符串为前缀。
  • 可以根据该结点的标志为是否为 true,判断树中是否包含此字符串

判断是否为前缀

 public boolean startsWith(String prefix) {
        Trie node =searchPrefix(prefix);

        return node!=null ;
    }

判断是否包含某字符串

 public boolean search(String word) {
        Trie node =searchPrefix(word);

        return node!=null && node.isEnd;
    }

完整代码:

package com.dyit.tanruike;

//可以吧Trie看作一个结点
class Trie {
    Trie[] child;//保存下一个字符
    boolean isEnd;//如果是字符串的结尾 则为tree
    public Trie() {
        child = new Trie[26];//总共有26个单词
        isEnd = false;//根节点
    }

    /**
     * 插入操作
     * @param word 需要插入的字符串
     */
    public void insert(String word) {
        //首先拿到根tire
        Trie cur =this;
        //循环插入
        for (char ch : word.toCharArray()){
            //计算当前字符在数组中的位置
            int index = ch -'a';
            //保存此字符 如果这和索引所在的位置不为null 就说名有字符
           if (cur.child[index] ==null) {
               cur.child[index] = new Trie();
           }

            cur = cur.child[index];
        }
        //退出循环时 cur指向字符串的末尾 设为true
        cur.isEnd = true;
    }

    /**
     *
     * @param word 需要搜索的字符
     * @return  如果找到了字符串所代表的最后一个字符 就返回字符 如果没有此单词 就返回null
     */
    public Trie searchPrefix(String word){
        //拿到根trie
        Trie cur = this;
        //遍历
        for (char ch : word.toCharArray()){
            //计算位置
            int index = ch-'a';
            //如果字符所代表的位置为空 则返回null
            if (cur.child[index]==null){
                return null;
            }

            cur = cur.child[index];
        }
        //返回最后一个字符所代表的tire
        return cur;
    }

    /**
     *
     * @param word 判断是否保存此字符串
     * @return 结果
     */
    public boolean search(String word) {
        Trie node =searchPrefix(word);

        return node!=null && node.isEnd;
    }

    /**
     * 判断此字符串是否为前缀
     * @param prefix 需要判断的字符串
     * @return 结果
     */
    public boolean startsWith(String prefix) {
        Trie node =searchPrefix(prefix);

        return node!=null ;
    }
}


可以根据实际情况,自行添加其他属性,以达到扩展的目的。

你可能感兴趣的:(数据结构,数据结构,单词查找树,字典树,前缀树)