Trie树(压缩Trie树及Double-Array Trie)

来源:互联网 发布:亚裔女神asiafox 知乎 编辑:程序博客网 时间:2024/06/05 14:38
又称字典树或者前缀树,一种用于快速检索的多叉树结构;英文字母的Trie树为26叉树,数字的Trie树为10叉树;All the descendants of a node have a common prefix of the sequence associated with that node, and the root is associated with the empty sequence. 由于不同的sequence使用公共的前缀,所以Trie树可以节省大量空间;但如果sequence仅有很少的公共前缀时,Trie树耗用较大的空间; 


Trie树中根节点为空字符,其他每个节点仅包含一个字符;从根节点到某一个终止节点的路径上经过的字符连接起来就是对应的string;Trie树中查找长度为M的string的时间复杂度为O(M),BST树中查找长度为M的string则需要O(MlogN),N为树中的节点数,则logN为树的高度,并且前提是BST为平衡树,Trie树的时间复杂度不受树是否平衡的影响;对于Hash表而言,其也可以实现查找,但是Trie树可以实现Closest Fit,也就是近似查找,Hash表不能实现近似查找;同时,Hash表有插入冲突需要解决;
 




Trie树中有两类节点,元素节点和分支节点,前者表示一条完整路径的终结,后者表示路径中的一个节点;Trie树的应用包括字典查找(Dictionary String Search)和近似匹配算法(Approximate Matching Algorithm);Trie树有三种结构:Standard Trie,Compressed Trie和Suffix Trie;标准Trie其实就是Prefix Trie;由于string本身可以存在一个单独的string1是另一个单独的string2的前缀,但是Trie树中规定所有stirng都是从根节点到叶子节点的完整路径,所以实际实现中需要在所有string最后引入一个$字符标志结束;


由于使用树+指针实现Trie树非常耗用内存,所以首先可以将原始Trie树进行压缩,也就是只有单个子节点的节点可以合并成一个节点;同时可以使用Double-Array Trie作为Trie树的实现:


#define MAX_NUM 26
/**
 * 表示两种类型的节点
 * */
enum NodeType {
        COMPLETED,
        UNCOMPLETED
};
/**
 * child指针数组存储a-z字母对应的索引
 * */
struct Node {
        NodeType type;
        char ch;
        Node *child[MAX_NUM];
};


Node *root;


Node* CreateNode(char ch) {
        Node *node=new Node();
        node->ch=ch;
        node->type=UNCOMPLETED;
        for(int i=0;i<MAX_NUM;i++)
                node->child[i]=NULL;
        return node;
}
/**
 * 初始化:将根节点创建为空字符的节点
 * */
void Init() {
        root=CreateNode('');
}


void Clean(Node *root) {
        if(root==NULL) return;
        for(int i=0;i<MAX_NUM;i++) {
                /**
                 * 首先递归处理子节点
                 * */
                Clean(root->child[i]);
        }
        /**
         * 删除动态内存
         * */
        delete [] root->child;
        /**
         * 删除节点本身
         * */
        delete root;
}


bool IsExisted(char *string,int length) {
        Node *index=root;
        Node *temp;
        int i;
        for(i=0;i<length;i++) {
                temp=index->child[string[i]-'a'];
                /**
                 * 如果某一个字符对应的指针位置为NULL,说明
                 * 此字符不存在
                 * */
                if(temp==NULL)
                        break;
                index=index->child[string[i]='a'];
        }
        /**
         * 仅当string匹配完全,并且trie树正好到达结束节点
         * 才成功返回
         * */
        if((i==length) && (index->type==COMPLETED))
                return true;
        else
                return false;
}




void InsertNew(char *string, int length) {
        Node *index=root;
        Node *temp;
        int i;
        for(i=0;i<length;i++) {
                temp=index->child[string[i]-'a'];
                if(temp==NULL)
                        /**
                         * 新插入的string的每一个字符都创建一个节点
                         * */
                        temp=CreateNode(string[i]);
                index=index->child[string[i]-'a'];
        }
        /**
         * 最后一个节点需要为结束节点
         * */
        index->type=COMPLETED;
}


参考连接:
http://linux.thai.net/~thep/datrie/datrie.html
http://hxraid.iteye.com/blog/618962
0 0
原创粉丝点击