标准trie树的Java实现

        trie树也叫字典树,网上各种资料和解释都是说它的效率比哈希表要高,在这里我先不做说明和比较,在后续的文章中我会对哈希算法、哈希表、hashmap都会有介绍,这里主要是搞清楚这个trie树的基本原理和具体实现。

       trie树的基本原理就是拿空间来换时间,什么个意思呢,现在以几个英文单词为例,”abc”,”abcde”,”acd”,”ecd”,我想要去查找他们,最原始的办法就是在字典取到所有的单词,再利用字符串匹配(这个的具体实现就比较多了)。很明显在字符串匹配的那一块将是症结所在,原理都是将字符串拆成一个个的字符,再去两两匹配,可以想象如果不对存放单词的那个库进行结构化那将是多么巨大的灾难,而trie树就是用来优化字典的结构。还以英文单词为例,再怎么复杂的单词都是由26个字母组成的,只不过是在长度和排列顺序上不一样而已,那就好办了,不就是匹配么,说穿了就是从单词的第一个字母开始,一个接着一个第往下找,那我就建一个数一样的结构,分层来处理不就OK了?trie树的基本原理就是这样。先创建一个根节点,什么都不干,就是相当于一个头指针的作用,然后第一层就是放单词的首字母,接下来再在每一个首字母节点下面同样操作,一次录入直到单词完结,那么问题来了我怎么确定到哪是一个单词,简单,在该处存一个变量做判断不就完事,如下图(从网上copy得到):

《标准trie树的Java实现》

     至此,我们可以得到一个trie树的最核心的结构trieNode它至少要有这么几个属性,自己本身的值value,自己下面的子节点 sons和判断该处是否是一个单词的结尾isEnd,有了这个之后后面的事情就简单了。具体java代码如下:

<span style="font-size:14px;">package TrieTree;
public class myTrie {
    private int CHAR_SIZE=26;//由于这里是先做英文匹配,共26个英文字母
    private TrieNode root;//根节点,不存储任何数据,相当于一个头指针
    public myTrie() {
        root=new TrieNode();
    }
    //插入一个单词
    public  void insertWord(String word){
        if(word==null||word.trim().equals("")){
            return ;
        }
        //1.转换成小写
        word=word.toLowerCase();
        //2.转换成字符数据
        char [] letters=word.toCharArray();
        //3.开始插入
        TrieNode node=root;
        for(int i=0;i<letters.length;i++){
            int pos=letters[i]-'a';//确定每一个字符在数组中的位置
            if(node.sons[pos]==null){
                TrieNode td=new TrieNode();
                td.value=letters[i];
                node.sons[pos]=td;
            }else{
                node.sons[pos].num++;
            }
            node=node.sons[pos];
        }
        node.isEnd=true;
    }
    //匹配一个单词
    public boolean findWord(String word){
        if(word==null||word.trim().equals("")){
            return false;
        }
        word=word.trim().toLowerCase();
        TrieNode node=root;
        char[] letters=word.toCharArray();
        for(int i=0;i<letters.length;i++){
            int pos=letters[i]-'a';
            if(node.sons[pos]==null){
                return false;
            }else{
                node=node.sons[pos];
            }
        }
        return node.isEnd;
    }
    //构建树的节点类
    private class TrieNode{
        private int num;//记录通过该节点的数目
        private TrieNode [] sons;//子节点
        private char value;//该处节点的值
        private boolean isEnd;//标记是否是一个单词的结尾
        public TrieNode() {
            num=1;
            sons=new TrieNode[CHAR_SIZE];
            isEnd=false;
        }
    }
}</span>

其中num属性主要是用来统计单词前缀的,这里面没有做写其他的方法,诸如遍历等;还有这里是进行英文匹配,中文匹配原理是一样的,但中文的单字有几万个,如果每一个节点都分配那么多的空间是不现实的,所以一种解决方法是每一个字开头组成一棵树,再将所有的树汇集成森林存在磁盘里面;由于中文的词语比较短很少有5个以上的所以树的高度不高,主要消耗在内部的匹配。

     关于trie树的效率以及和其他树的比较在这里不详细讨论,后面会陆续讨论其他几种,然后再去做具体的 比较




    原文作者:Trie树
    原文地址: https://blog.csdn.net/my_sunshine_y/article/details/50497936
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞