Perl 前缀树实现
前缀树,用来处理大量字符串的查找、排序,也称为字典树,可以代替hash table。 http://en.wikipedia.org/wiki/Trie 以下翻译自Wikipedia: The following are the main advantages of tries over?binary search trees?(BSTs):
相对二叉搜索树的优点: The following are the main advantages of tries over?hash tables:
相对hash table 的优点: 1. Trie 的迭代是已经排序的,而hash table 则是根据hash 函数的结果排序。 2. Trie 可以用来完成最大前缀字符串匹配,hash table不支持。 3. Trie 插入性能好于hash table。当hash table分配已满并继续增加key,需要重建index,这种情况下非常耗费资源。因而在边界情况下Trie有更好的的插入性能。 4. Trie 不需要计算hash值,因而对于短字符串有更加快速。 As replacement of other data structuresAs mentioned,a trie has a number of advantages over binary search trees.[4]?A trie can also be used to replace a?hash table,over which it has the following advantages:
Trie可以用来代替hash table,有如下优点: 1. 最坏情况下查找更加高效,需要O(m)时间。不完美的hash table会产生key碰撞。 2. Trie 没有key碰撞。 3. Trie 只有在允许一个key存储多个值的情况下才有类似hash碰撞发生。 4. 当更多的值插入时不需要hash 函数或者调整hash。 5. Trie 提供经过字典排序的key。 Tries do have some drawbacks as well:
Perl代码: use Data::Dumper; # 默认只支持字符串的输入 sub trie_tree{ my $root = {}; for(@_){ insert($root,$_); } return $root; } # 方便起见,每次只处理一个连续字符串 sub insert{ my ($tree,$str) = @_; # 不包含字符串情况下返回 return unless $str =~ /[a-zA-Z]/; # 所有节点都存小写字符 $str =~ /([a-zA-Z]+)/; my @tmp = split //,lc $1; my $root = $tree; for(@tmp){ if($root->{$_}){ $root = $root->{$_}; } else{ # count用来标记一个完整的字符串到此结束如不为0,count值表示字符串出现的次数 $root->{$_} = {count=>0,}; $root = $root->{$_}; } } $root->{count} ++; } # 返回值 # undef 完整字符串未出现 # 0 查找字符串作为前缀字符串出现 # N 字符串出现N次 sub search{ my ($tree,$str) = @_; return if $str =~ /[^a-zA-Z]/; my @tmp = split //,lc $str; my $root = $tree; for(@tmp){ if($root->{$_}){ $root = $root->{$_}; } else{ return } } return $root->{count}; } # 用三个array 来标记中间信息,例子两个字符串a,bc # [root] # [[a,b]] <- 判断循环条件 # [] # 第一次取a节点 # [root,a] # [[b],[]] # [a] # 第二次取空节点,出栈 # [root] # [[b]] <- 判断循环条件 # [] # 第三次取b节点 # [root,b] # [[],[c]] <- 判断循环条件 # [b] # 第四次取c节点 # [root,b,c] # [[],[]] <- 判断循环条件 # [b,c] # 第五次取空节点 # [root,b] # [[]] <- 判断循环条件 # [b] # 第六次取空节点 # [root] # [] <- 判断循环条件为空,结束 # [] sub travel{ my ($tree) = @_; # 储存当前节点指针 my @node = ($tree); # 储存当前节点下的字符序列 my @node_chars = ([grep { $_ ne 'count' } sort keys %$tree ]); # 储存字符串 my @chars = (); while(@node_chars){ if(! @{$node_chars[-1]}){ pop @node; pop @node_chars; pop @chars; next; } else{ # 存储信息压栈顺序要注意,否则会出错 my $char = shift @{$node_chars[-1]}; push @chars,$char; if($node[-1]->{$char}->{count} > 0){ print join('',@chars),' => ',$node[-1]->{$char}->{count},"n"; } push @node_chars,[grep { $_ ne 'count' } sort keys %{ $node[-1]->{$char} } ]; push @node,$node[-1]->{$char}; } } } my $tree = trie_tree(qw(this is just a testing)); insert($tree,'and'); insert($tree,'testing'); #~ print Dumper $tree; #~ print search($tree,'testing'); #~ print search($tree,'and'); travel($tree);输出: a => 1 and => 1 is => 1 just => 1 testing => 2 this => 1 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |