trie树

Trie树

1基本描述

Tire树又称字典树,单词查找树,或者前缀树,是一种用于快速检索的多叉数据结构。

2用途

利用公共前缀来节约存储空间,一般用于构建字典,构建词库,扫描词库匹配。缺点是内存消耗非常大。

3设计之前考虑的一些性质

根节点为空,除他以外的每个子节点都可以不存储字符(只不过要知道哪个字符对应哪个branch,可以用字符映射到对应的分支,一一对应)。存储字符也可以。

单词必须有结尾,所以必须在每个节点处设置结束标记。

根据字符的数目设置好分支数目(也就是指向后面节点的指针数目)。

4具体实现

#define MAX_Bra 10 //最大分支数目,如果字符串是电话号码可以用0到9表示 所以设置10个分支,如果为字母设置26个分支。
struct trie_node{
	bool isStr;//字符是否结束,为真时结束,表示是一个字符串
	trie_node* branch[MAX_Bra];//表示分支的指针数组,实现要指明哪个字符对应哪个分支,如果是字母,a可以对应0分支//其他类推 'a'-'a'=0   'b'-'a'=1 如果word中字符较多,可以将每个字符转化为唯一的分支下标,就是这样:branch(charsToindex(word[i]))。这里charsToindex(word[i])就是字符对应的分支号了。
	trie_node()
   	{
      	 	isStr = false;
     	 	memset(next,NULL,sizeof(branch));
  	 }	
};

附上一张图,为了更好的理解trie树。

该trie树存有abc、d、da、dda四个字符串,如果是字符串会在节点的尾部进行标记。没有后续字符的branch分支指向NULL

trie树_第1张图片

5简单的实现一些操作

首先定义一个类:Trie_tree,他拥有插入字符串,查找字符串,删除字符串等操作。

class Trie_tree{
public:
	Trie_tree();
	void insert_word(const char*word);
	bool search_word(char*word);
	void delete_word(char *word);
private:
	trie_node *root;
};
Trie_tree::Trie_tree(){
	root = new trie_node();
}
关于插入字符串的操作:

插入时首先匹配字符串的第一个字符,(根据此字符对应的分支下表来匹配,如第一个字符为d,就看分支branch[*word - 'a']是否为空)。为空时表示不存在这个字符,那么动态开辟节点用来存储这个字符。存储到branch[*word - 'a']中。当插入一个字符之后,位置要改变为当前插入的分支,current = current->branch[index];最后达到字符串的尾部,将isStr置为真,表示此处有一个字符串。

简单实现如下:

Trie_tree::insert_word(word){
	trie_node *current_node = root;
	while (*word)
	{
		if (current_node->branch[*word-'a'] == NULL)
		{
			trie_node tmp = new trie_node();
			current_node->branch[*word-'a'] = tmp;
		}
		current_node = current_node->branch[*word-'a'] ;
		word++;
	}
	current_node->isStr = true;//字符串结束之后要设置标志位
}
字符串的查找操作:

根据字符对应的指针不断的向下遍历树的分支,如果能够找到,则对应的节点不为空并且它的isStr标志位为真。

Trie_tree::search_word(char*word){
	trie_node *current_node = root;
	while (*word&¤t_node)
	{
		current_node = current_node[*word-'a'];
		word++;
	}
	return (current_node!=NULL&¤t_node->isStr);
}

字符串的删除

首先要找到字符串,如果存在就删除,如果不存在就报错。如何删除呢?

如果字符串是别的词汇的前缀,那么直接销毁最后一个字符的分支的标志位,表示不存在这个字符了。否则,从字符串的最后一个字符回溯上去,找到第一个有至少两个非空指针的节点,从这个节点开始销毁此字符串后面几个节点。麻烦的就是找出这个分叉节点了。

上面只是简单的实现,利用双数组实现可以大大减小内存的使用具体如下:

http://linux.thai.net/~thep/datrie/datrie.html


6时间复杂度分析

插入和查找的时间复杂度均为O(n),n为字符串的长度。

空间复杂度约为:26*(n1+1)+26*(n2+1)+26*(n3+1)...(表达式因为和单词的前缀有关,如果单词前缀重复的多,用的指针空间应该更小,所以不好准确表示)。

7一些应用

排序:tire树是一颗多叉树,遍历整棵树,输出相应的字符串就是按字典排序的结果。

作为其他数据结构和算法的辅助:如AC自动机和后缀树。

还可以用于字符串检索,字符串的最长公共前缀。

关于应用这篇文章讲了一点,http://dongxicheng.org/structure/trietree/

PS:关于删除某一个字符串用别的数据结构实现,应该删除起来更方便。以后研究之后继续补充。






你可能感兴趣的:(trie树)