Trie 来自于单词 retrieval,是一种多叉树结构,可以很好的存储一个指定的字母表上的字符串。Trie 已经被用作英文字典,例如用于存储拼写检查程序和自然语言理解程序中用到的单词。
给定一组字符串:an,ant,all,allot,alloy,aloe,are,ate,be
相应的Trie 如下图:
中心思想是,所有有共同词干或共同前缀的字符串会链接到同一个节点上。当字符串是在字母表{a..z}上的单词时,一个节点最多有27个子节点—每一个字母对应一个,加上终止符对应的一个。
字符串中的所有字符都可以通过从根节点到叶节点的遍历来查找到。叶节点代表了一个字符串的结束符。Trie中所有的字符串可以通过深度优先遍历来查找到。
一种时间复杂度很高效但是空间复杂度严重浪费的实现算法如下(Pascal):
type trie = ^ node;
node = record
subtrie :array['a'..'z'] of trie;
IsEndOfWord :boolean
end;
我们可以看到该算法用27叉树来表示Trie。这种方法是很浪费的,因为很多节点的某个字符对应的子节点是被设置成nil的。另一方面,字符串中每一个字符的查找都是随机存储的,即O(p)时间即可查找到一个长度为p 的字符串是否在Trie中。
function find(word:string; length:integer; t:trie):boolean;
functionf(level:integer; t:trie):boolean;
beginif level=length+1 then
f:=t^.IsEndOfWord
else if t^.subtrie[word[level]]=nil then
f:=false
else f:=f(level+1, t^.subtrie[word[level]])
end{f};
begin find := f( 1, t )
end{find}
另一种实现Trie的方法是,用链表来表示。每一个节点最多有27个子节点。每一个子节点用一个<char,trie>对儿来表示。这种方式对字符串的每一个字符都需要进行查找算法才能判断是否存在。即对一个长度为p的字符串需要O(plogn)复杂度才能得到(n为字母表长度)。但是这种方法可以叶节点的空间,毕竟一个树的叶比叉更多。
Notes
- The height of a trie is the length of the longest key in the trie.
- E. Fredkin. Trie Memory. Comm. ACM 3(9) pp490-499 Sept. 1960.
- See [PATRICIA trees].
- See [Suffix Trees] for string searching etc..