• 前缀树(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"));
    
            }
    
        }
    }
    

      

  • 相关阅读:
    (转)分析索引快速获取索引信息
    ORA-16014报错解决
    (转)关于索引的一点知识
    (转)CentOS搭建Nagios监控
    (转)Autotrace工具使用——小工具,大用场
    Using ROWNUM in Oracle
    oracle回收站
    DBA 思想天空笔记
    Oracle trunc函数
    MVC5中使用SignalR2.0实现实时聊天室
  • 原文地址:https://www.cnblogs.com/SkyeAngel/p/8954888.html
Copyright © 2020-2023  润新知