您的位置:首页 > 其它

字典树存在的意义

2012-07-16 09:28 155 查看
1.字典树

  曾经遇到这样一个问题:很多单词,这些单词只含小写字母,并且不会有重复的单词出现,现在要统计出以某个字符串为前缀的单词数量,单词本身也是自己的前缀。先看看用常规的方法解决这个问题的复杂度。假设单词表容量为M,需要统计的前缀数量为N,前缀的平均长度是L,则常规算法思路是:对于每个前缀搜索每个单词,看看这个前缀是不是这个单词的前缀,如果是数量+1。这样的话时间复杂度为O(N*M*L),如果N相当大的话,这个算法的复杂度将无法接受啦。其实这就是字典树的典型应用啦。

  我们先学习一下字典树,在解决上面的问题。字典树又称trie树,从名字上看很显然是一种树形结构了。字典树有以下几个特点:1.利用串的公共前缀,节约内存;2.根结点不包含任何字母;3.其余结点仅包含一个字母;4.每个结点的子节点包含字母不同。看看一个例子吧:下面就是一个字典树(图片来自百度百科)

View Code

struct Trienode
{
int count;
bool isWord;//判断当前字母是否是单词最后一个字母的标志
node *next[26];//后继结点可能是26个小写字母
node()//构造函数
{
count = 1;
isWord = false;
for(int i = 0 ; i < 26 ; i++)
{
next[i] = NULL;
}
}
};


  看出来了吧,加入了一个count成员,用来记录每个节点在单词中出现的次数,然后在对应的插入操作(Insert)中,每次插入时经过的节点作count++操作;这样进行搜索(Search)时,若搜索成功只需要返回搜索终止节点的count变量的值,就是以某个字符串为前缀的单词总数啦。现在不妨来分析一下算法的时间复杂度,每次查找的时间复杂度是O(L),L是要搜索的前缀平均长度。现在有N个前缀需要处理,那么整个时间复杂度就是O(N*L),然后还要加上建字典树的时间复杂度,单词数为M,不妨设单词的平均长度是L',那么建字典树的时间复杂度就是O(M*L'),所以整个算法的时间复杂度是O(N*L + M*L'),想必之前的复杂度O(N*M*L),这是个不小的改进。当然我们也说了,这引入一些辅助空间,加快了搜索的速度。实际应用中M往往是大量的,比如搜索引擎中的字典,要在百度中进行搜索,那么采用字典树的地位就举足轻重啦。采用字典树可以大大的降低搜索的复杂度。

[b]2.字典树的应用和好处[/b]

那么字典树到底有哪些典型的应用呢?

1.字典树在串的快速检索中的应用。
  给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。在这道题中,我们可以用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。

2. 字典树在“串”排序方面的应用
  给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可。

3. 字典树在最长公共前缀问题的应用
  对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为最近公共祖先问题。

使用字典树的好处:

1.利用字符串的公共前缀来节约存储空间。

2.最大限度地减少无谓的字符串比较,查询效率比较高。例如:若要查找的字符长度是5,而总共有单词的数目是26^5=11881376,利用trie树,利用5次比较可以从11881376个可能的关键字中检索出指定的关键字,而利用二叉查找树时间复杂度是O( log2n ),所以至少要进行log211881376=23.5次比较。可以看出来利用字典树进行查找速度是比较快的。


学习中的一点总结,欢迎拍砖哦^^

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: