前缀树(Trie树,字典树)

给出字符串,如“abc”

从头结点开始,依次检查,有没有走向a的路,如果没有,就新建出来,a作为路上的值(不是结点的值),如果有的话,就复用

在字符串的结尾处的结点的值+1,表示有一个是以该字符串结尾的

1.可以查是否某个字符串是以某个字符串为前缀的

2.还可以查 添加了几次该前缀  (有多少字符串是以该结点结尾的)

3.还可以查有多少个字符串是以字符串作为前缀的(前缀的词频是多少)(有多少字符串到达过该结点)

 

 

插入字符串:public void insert(String str)

删除字符串:public void delete(String str)

在前缀树中查询字符串出现的次数:public int search(String str)

在前缀树中查询以str字符串为前缀的个数:public int prefixNumber(String str)

 

public class TrieTree {
    //前缀树的结构
    public static class TrieNode{
        //表示扫过当前结点多少次
        public int path;
        //表示以当前结点结尾的次数
        public int end;

        //表示当前结点的下一个结点(从a-z)  同时,数组中对应的位置就是a-z字母的顺序
        // 如果想表示其他类型的,可以使用HashMap<Integer, TrieNode> nexts;
        // key表示的是边的ASCII码,value表示对应的下一个结点
        public TrieNode[] nexts;


        public TrieNode(){
            path = 0;
            end = 0;
            nexts = new TrieNode[26];
        }
    }


    public static class Trie{
        //前缀树的头结点 为空
        private TrieNode root;
        public Trie(){
            root = new TrieNode();
        }

        /**
         * 将一个字符串加入前缀树,即向前缀树中添加路径和结点,
         * 首先检查前缀树中是否含有当前结点,
         * 如果存在的话,则将其路径上的path++,end++,
         * 如果不存在某几个结点的话,则创建出来
         * @param str
         */
        public void insert(String str){
            if(str == null || str.length() == 0) return;
            char[] ch = str.toCharArray();

            TrieNode trieNode = root;

            for(int i = 0; i < ch.length; i++){
                int index = ch[i] - 'a';
                //该元素不存在,则创建出来
                if(trieNode.nexts[index] == null){
                    trieNode.nexts[index] = new TrieNode();
                }
                trieNode = trieNode.nexts[index];
                trieNode.path++;
            }
            trieNode.end++;
        }


        /**
         * 删除指定字符串对应在前缀树中的路径
         * 在前缀树中查找,然后依次将其path-1,
         * 当path==0时,直接将其置为null即可(后面的结点都可以不要了)
         * @param str
         */
        public void delete(String str){
            if(str == null || str.length() == 0) return;
            char[] ch = str.toCharArray();
            TrieNode trieNode = root;

            for(int i = 0; i < ch.length; i++){
                int index = ch[i] - 'a';
                if(--trieNode.nexts[index].path == 0){
                    trieNode.nexts[index] = null;
                    return;
                }
                trieNode = trieNode.nexts[index];
            }
            trieNode.end--;
        }


        /**
         * 查询一个字符串在前缀树中出现了多少次
         * 如果一路下来都存在,则返回end中的值,
         * 如果过程中含有不存在的值,则返回0
         * @param str
         * @return
         */
        public int search(String str){
            if(str == null || str.length() == 0) return 0;

            char[] ch = str.toCharArray();

            TrieNode trieNode = root;
            for(int i = 0; i < ch.length; i++){
                int index = ch[i] - 'a';
                if(trieNode.nexts[index] == null) return 0;
                trieNode = trieNode.nexts[index];
            }
            return trieNode.end;
        }


        /**
         * 查找以str为前缀的字符有多少
         * 即查找以str为路径的path是多少
         * @param str
         * @return
         */
        public int prefixNumber(String str){
            if(str == null || str.length() == 0) return 0;
            char[] ch = str.toCharArray();
            TrieNode trieNode = root;

            for(int i = 0; i < ch.length; i++){
                int index = ch[i] - 'a';
                if(trieNode.nexts[index] == null) return 0;
                trieNode = trieNode.nexts[index];
            }
            return trieNode.path;
        }

        public static void main(String[] args) {
            Trie trie = new Trie();
            System.out.println(trie.search("zuo"));
            trie.insert("zuo");
            System.out.println(trie.search("zuo"));
            trie.delete("zuo");
            System.out.println(trie.search("zuo"));
            trie.insert("zuo");
            trie.insert("zuo");
            trie.delete("zuo");
            System.out.println(trie.search("zuo"));
            trie.delete("zuo");
            System.out.println(trie.search("zuo"));
            trie.insert("zuoa");
            trie.insert("zuoac");
            trie.insert("zuoab");
            trie.insert("zuoad");
            trie.delete("zuoa");
            System.out.println(trie.search("zuoa"));
            System.out.println(trie.prefixNumber("zuo"));

        }

    }
}

  

posted @ 2018-04-26 20:32  SkyeAngel  阅读(803)  评论(0编辑  收藏  举报