是 特里和基数特里数据结构是一回事吗?
如果它们相同,那么基数根(AKA Patricia trie)是什么意思?
radix trie
文章标题为Radix tree
。此外,术语“基数树”在文献中被广泛使用。如果有任何呼叫尝试“前缀树”,对我来说更有意义。毕竟,它们都是树数据结构。
radix = 2
,这意味着您可以通过一次查找输入字符串的位来遍历树log2(radix)=1
。
是 特里和基数特里数据结构是一回事吗?
如果它们相同,那么基数根(AKA Patricia trie)是什么意思?
radix trie
文章标题为Radix tree
。此外,术语“基数树”在文献中被广泛使用。如果有任何呼叫尝试“前缀树”,对我来说更有意义。毕竟,它们都是树数据结构。
radix = 2
,这意味着您可以通过一次查找输入字符串的位来遍历树log2(radix)=1
。
Answers:
基数树是trie的压缩版本。在特里树中,在每个边上都写一个字母,而在PATRICIA树(或基数树)中则存储整个单词。
现在,假设你有话hello
,hat
和have
。要将它们存储在trie中,它看起来像:
e - l - l - o
/
h - a - t
\
v - e
您需要九个节点。我将字母放置在节点中,但实际上它们标记了边缘。
在基数树中,您将具有:
*
/
(ello)
/
* - h - * -(a) - * - (t) - *
\
(ve)
\
*
而且您只需要五个节点。在上图中,节点是星号。
因此,总的来说,基数树占用更少的内存,但是很难实现。否则,两者的用例几乎相同。
我的问题是Trie数据结构和Radix Trie是否相同?
简而言之,没有。类别板蓝根特里描述的特定类别的特里,但这并不意味着所有的尝试都是基数尝试。
如果它们不相同,那么Radix trie(又名Patricia Trie)是什么意思?
我想你不是要写您的问题中,因此请纠正。
同样,PATRICIA表示一种特定类型的基数特里,但并非所有基数尝试都是PATRICIA尝试。
“Trie树”描述适合用作一个关联数组,其中枝条或边对应于树数据结构部件的一个关键的。的定义这里,部分相当模糊,因为尝试的不同实现使用不同的位长来对应边。例如,二进制特里树每个节点具有两个边,分别对应于0或1,而16向特里树每个节点具有16个边,对应于四个位(或十六进制数字:0x0至0xf)。
从Wikipedia检索到的此图似乎描绘了一个Trie,至少(包括)键“ A”,“ to”,“ tea”,“ ted”,“ ten”和“ inn”被插入:
如果该尝试存储键“ t”,“ te”,“ i”或“ in”的项,则每个节点上都需要存在额外的信息,以区分零节点和具有实际值的节点。
正如Ivaylo Strandjev在他的回答中所描述的,“基数基”(trix trie)似乎描述了浓缩普通前缀部分的基音。考虑一个256路Trie,它使用以下静态分配为键“ smile”,“ smiled”,“ smiles”和“ smiling”编制索引:
root['s']['m']['i']['l']['e']['\0'] = smile_item;
root['s']['m']['i']['l']['e']['d']['\0'] = smiled_item;
root['s']['m']['i']['l']['e']['s']['\0'] = smiles_item;
root['s']['m']['i']['l']['i']['n']['g']['\0'] = smiling_item;
每个下标访问一个内部节点。这意味着要检索smile_item
,您必须访问七个节点。八个节点访问对应于smiled_item
和smiles_item
,九个对应于smiling_item
。对于这四个项目,总共有十四个节点。但是,它们都具有相同的前四个字节(对应于前四个节点)。通过压缩这四个字节以创建root
与对应的['s']['m']['i']['l']
,已经优化了四个节点访问。这意味着更少的内存和更少的节点访问,这是一个很好的指示。可以递归应用优化,以减少访问不必要的后缀字节的需要。最终,您到达的位置是只比较由Trie索引的位置处的搜索键和索引键之间的差异。这是一个基数特里。
root = smil_dummy;
root['e'] = smile_item;
root['e']['d'] = smiled_item;
root['e']['s'] = smiles_item;
root['i'] = smiling_item;
要检索项目,每个节点都需要一个位置。使用“ smiles”的搜索关键字和root.position
4的a,我们可以访问root["smiles"[4]]
,恰好是root['e']
。我们将此存储在名为的变量中current
。current.position
是5,这是"smiled"
和之间的差值的位置"smiles"
,因此下一次访问将是root["smiles"[5]]
。这将我们带到smiles_item
,以及字符串的结尾。我们的搜索已终止,并且已检索到该项目,而只有三个节点访问权限而不是八个节点访问权限。
PATRICIA trie是基数尝试的一种变体,对于该基数尝试,应该永远只有n
用于包含n
项的节点。在我们的粗略表明基数线索上述伪代码中,总共有五个节点:root
(这是一个无参节点;它不包含任何实际值), ,,root['e']
和。在PATRICIA的trie中,应该只有四个。由于PATRICIA是二进制算法,因此让我们通过二进制查看这些前缀的不同之处。root['e']['d']
root['e']['s']
root['i']
smile: 0111 0011 0110 1101 0110 1001 0110 1100 0110 0101 0000 0000 0000 0000
smiled: 0111 0011 0110 1101 0110 1001 0110 1100 0110 0101 0110 0100 0000 0000
smiles: 0111 0011 0110 1101 0110 1001 0110 1100 0110 0101 0111 0011 0000 0000
smiling: 0111 0011 0110 1101 0110 1001 0110 1100 0110 1001 0110 1110 0110 0111 ...
让我们考虑节点按上面显示的顺序添加。smile_item
是这棵树的根。粗体显示的区别在于的最后一个字节"smile"
,位于bit36。到现在为止,我们所有的节点都具有相同的前缀。smiled_node
属于smile_node[0]
。之间的差"smiled"
和"smiles"
发生在43位,其中"smiles"
有一个“1”比特,所以smiled_node[1]
是smiles_node
。
而不是使用NULL
作为分支机构和/或额外的内部信息,表示当搜索终止,树枝链接回了树的地方,所以当偏移测试搜索终止减小而不是增加。这是这样一棵树的简单示意图(尽管您会看到,尽管PATRICIA实际上更像是一个循环图,而不是一棵树),该树包含在下面提到的Sedgewick的书中:
尽管在过程中会丢失PATRICIA的某些技术属性(即,任何节点都包含与其之前的节点相同的公共前缀),但可能会出现涉及变长密钥的更复杂的PATRICIA算法:
通过这样分支,有很多好处:每个节点都包含一个值。包括根。结果,代码的长度和复杂性变得更短,实际上可能更快一些。跟踪至少一个分支和至多k
分支(其中k
是搜索关键字中的位数)以找到项目。节点很小,因为它们每个都只存储两个分支,这使得它们非常适合优化缓存位置。这些特性使PATRICIA成为我迄今为止最喜欢的算法...
为了简化我即将来临的关节炎的严重程度,我将在此省略其描述,但是如果您想进一步了解PATRICIA,可以查阅诸如Donald Knuth的“计算机编程艺术,第3卷”之类的书。 ,或Sedgewick撰写的“ {您最喜欢的语言}中的算法,第1-4部分”。
特里:
我们可以使用一种搜索方案,而不是将整个搜索键与所有现有键进行比较(例如哈希方案),还可以将搜索键的每个字符进行比较。按照这个想法,我们可以构建一个具有三个现有键的结构(如下所示):“ dad ”,“ dab ”和“ cab ”。
[root]
...// | \\...
| \
c d
| \
[*] [*]
...//|\. ./|\\... Fig-I
a a
/ /
[*] [*]
...//|\.. ../|\\...
/ / \
B b d
/ / \
[] [] []
(cab) (dab) (dad)
本质上,这是一个M叉树,其内部节点表示为[*],叶节点表示为[]。这种结构称为特里。每个节点的分支决策可以保持等于字母的唯一符号的数量,例如R。对于小写英文字母az,R = 26;对于小写英文字母az,R = 26。对于扩展的ASCII字母,R = 256,对于二进制数字/字符串,R = 2。
紧凑型TRIE:
通常,特里树中的节点使用size = R的数组,因此当每个节点的边数较少时,会浪费内存。为了避免内存问题,提出了各种建议。基于这些变化,特里树也被称为“ 紧凑特里树 ”和“ 压缩特里树 ”。尽管很少有一致的命名法,但紧凑的trie的最常见版本是通过在节点具有单个边缘时对所有边缘进行分组来形成的。使用此概念,带有键“ dad”,“ dab”和“ cab” 的上述(图I)尝试可以采用以下形式。
[root]
...// | \\...
| \
cab da
| \
[ ] [*] Fig-II
./|\\...
| \
b d
| \
[] []
请注意,“ c”,“ a”和“ b”中的每一个都是其相应父节点的唯一边缘,因此,它们被合并为单个边缘“ cab”。类似地,“ d”和“ a”合并为标记为“ da”的单个边。
基数Trie树:
术语基数,在数学,指数系统的基站,并且它基本上表示以表示在该系统中任何数量的所需的唯一的符号的数目。例如,十进制表示的是基数十,而二进制表示的是基数二。使用类似的概念,当我们有兴趣通过底层表示系统的唯一符号的数量来表征数据结构或算法时,可以用术语“基数”标记该概念。例如,“基数排序”用于某些排序算法。按照相同的逻辑,特里的所有变体其特征(例如深度,内存需求,搜索未命中/命中运行时间等)取决于基础字母的基数,我们可以称它们为“ trie's”。例如,,未压缩和压缩的。特里当使用字母AZ,我们可以称之为一个基数26线索。仅使用两个符号(传统上为'0'和'1')的任何trie都可以称为基数2 trie。但是,以某种方式,许多文献仅将术语“基数特里”(Radix Trie)限制用于压实特里。
PATRICIA Tree / Trie的前奏:
有趣的是,甚至可以使用二进制字母表示字符串作为键。如果我们假设ASCII编码,然后一键“爸爸”,可以以二进制形式写在序列中的每个字符的二进制表示写,说为“ 01100100 01100001 01100100 ”写“d”的二进制形式,“A”,和依次为“ d”。使用此概念,可以形成三叉戟(带有基数2)。下面我们使用一个简化的假设来描述这个概念,即字母“ a”,“ b”,“ c”和“ d”来自较小的字母而不是ASCII。
图III的注释:如前所述,为了简化描述,我们假设一个字母只有4个字母{a,b,c,d},它们对应的二进制表示形式分别是“ 00”,“ 01”,“ 10”和“分别为“ 11”。这样,我们的字符串键“ dad”,“ dab”和“ cab”分别变为“ 110011”,“ 110001”和“ 100001”。其特里将如下图III所示(从左至右读取位,就像从左至右读取字符串一样)。
[root]
\1
\
[*]
0/ \1
/ \
[*] [*]
0/ /
/ /0
[*] [*]
0/ /
/ /0
[*] [*]
0/ 0/ \1 Fig-III
/ / \
[*] [*] [*]
\1 \1 \1
\ \ \
[] [] []
(cab) (dab) (dad)
PATRICIA Trie / Tree:
如果我们使用单边压缩来压缩上述二进制Trie(图III),则其节点数将比上面显示的要少得多,但是,节点数仍将大于3,即它包含的键数。 唐纳德·R·莫里森(Donald R. Morrison)发现了(1968年)一种创新的方法,该方法仅使用N个节点即可使用二进制特里树来描述N个键,并将其命名为PATRICIA。他的特里结构基本上摆脱了单一边缘(单向分支);并且这样做,他还摆脱了两种节点的概念–内部节点(不描述任何键)和叶节点(描述键)。与上面解释的压缩逻辑不同,他的尝试使用不同的概念,其中每个节点都包含一个密钥的多少位的指示,以跳过该分支以做出分支决策。他的PATRICIA trie的另一个特点是它不存储密钥-这意味着这种数据结构将不适合回答问题,例如列出与给定前缀匹配的所有密钥,但是对于查找某个密钥是否存在或该密钥非常有用。不在里。但是,此后,帕特里夏树(Patricia Tree)或帕特里夏特里(Patricia Trie)一词在许多不同但相似的意义上被使用,例如,表示紧凑的特里[NIST]或表示基数为2的基数特里[如微妙之处所示]。 WIKI中的方式]等。
特里这可能不是一个基数特里:
三元搜索特里(又名三元搜索树),通常缩写为TST是一种数据结构(所提出J.宾利和R.塞奇威克看起来非常相似,特里结构三路分支)。对于这样的树,每个节点都具有特征字母“ x”,因此分支决定是由键的字符是否小于,等于或大于“ x”来驱动的。由于此固定的3向分支功能,它为trie提供了一种内存有效的替代方法,尤其是当R(基数)非常大(例如Unicode字母)时。有趣的是,与(R-way)trie不同,TST 的特征不受R的影响。例如,TST的搜索缺失为ln(N)与R-way Trie的log R(N)相反。TST的存储器要求,不同于R-方式线索是NOT R的函数,以及。因此,我们应该小心地将TST称为基数三重奏。我个人不认为我们应该称它为基数三位一体,因为(据我所知)其特性不受其基础字母的基数R的影响。
uintptr_t
用作您的整数,因为似乎通常希望该类型(尽管不是必需的)存在。
radix-tree
不是有点烦人的人radix-trie
吗?此外,还有很多问题用它标记。