trie和radix trie数据结构之间有什么区别?


95

特里基数特里数据结构是一回事吗?

如果它们相同,那么基数根(AKA Patricia trie)是什么意思?


4
我是唯一发现标签radix-tree不是有点烦人的人radix-trie吗?此外,还有很多问题用它标记。
errantlinguist

@errantlinguist Wikipedia将radix trie文章标题为Radix tree。此外,术语“基数树”在文献中被广泛使用。如果有任何呼叫尝试“前缀树”,对我来说更有意义。毕竟,它们都是数据结构。
Amelio Vazquez-Reina

另外: “基数特里(AKA Patricia trie)是什么意思?” 假设基数树和PATRICIA树是一回事,但不是(例如,参见此答案)。PATRICIA树是通过运行PATRICIA 算法获得的树(FYI PATRICIA也是首字母缩写,代表“检索字母数字编码信息的实用算法”)。生成的树可以理解为具有的基数树radix = 2,这意味着您可以通过一次查找输入字符串的位来遍历树log2(radix)=1
阿梅利奥(Amelio Vazquez-Reina)

Answers:


118

基数树是trie的压缩版本。在特里树中,在每个边上都写一个字母,而在PATRICIA树(或基数树)中则存储整个单词。

现在,假设你有话hellohathave。要将它们存储在trie中,它看起来像:

    e - l - l - o
  /
h - a - t
      \
       v - e

您需要九个节点。我将字母放置在节点中,但实际上它们标记了边缘。

在基数树中,您将具有:

            *
           /
        (ello)
         /
* - h - * -(a) - * - (t) - *
                 \
                 (ve)
                   \
                    *

而且您只需要五个节点。在上图中,节点是星号。

因此,总的来说,基数树占用更少的内存,但是很难实现。否则,两者的用例几乎相同。


谢谢...您能给我提供学习Trie DS的好资源吗?这将对您有很大帮助...
Aryak Sengupta

我相信Wikipedia文章是我第一次实现Trie时唯一使用的东西。我并不是说这是完美的,但足够好。
Ivaylo Strandjev

1
我可以说在TRIE中搜索比基数树更快吗?因为在TRIE中,如果您想搜索下一个字符,则需要查看当前节点的子数组中的ith索引,而在基数树中,需要顺序搜索所有子节点。请参阅实施code.google.com/p/radixtree/source/browse/trunk/RadixTree/src/…– 2013
尝试

4
实际上,在基数树中,以相同字母开头的边不能超过一个,因此可以使用相同的常量索引。
Ivaylo Strandjev

1
@尝试算法Radix比TRIE快,这就是为什么值得进行压缩的原因。较少的节点要加载,而空间较少通常更好。也就是说,实施质量可能会有所不同。
Glenn Teitelbaum

68

我的问题是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_itemsmiles_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.position4的a,我们可以访问root["smiles"[4]],恰好是root['e']。我们将此存储在名为的变量中currentcurrent.position是5,这是"smiled"和之间的差值的位置"smiles",因此下一次访问将是root["smiles"[5]]。这将我们带到smiles_item,以及字符串的结尾。我们的搜索已终止,并且已检索到该项目,而只有三个节点访问权限而不是八个节点访问权限。


什么是PATRICIA trie?

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的某些技术属性(即,任何节点都包含与其之前的节点相同的公共前缀),但可能会出现涉及变长密钥的更复杂的PATRICIA算法:

复杂的PATRICIA图

通过这样分支,有很多好处:每个节点都包含一个值。包括根。结果,代码的长度和复杂性变得更短,实际上可能更快一些。跟踪至少一个分支和至多k分支(其中k是搜索关键字中的位数)以找到项目。节点很小,因为它们每个都只存储两个分支,这使得它们非常适合优化缓存位置。这些特性使PATRICIA成为我迄今为止最喜欢的算法...

为了简化我即将来临的关节炎的严重程度,我将在此省略其描述,但是如果您想进一步了解PATRICIA,可以查阅诸如Donald Knuth的“计算机编程艺术,第3卷”之类的书。 ,或Sedgewick撰写的“ {您最喜欢的语言}中的算法,第1-4部分”。


您能否帮助我理解“基数”一词的含义!我了解,以自然的方式,我们可以尝试通过允许多个符号/边合并为一条边来将TRIE变成紧凑的TRIE。但是,我无法辨别为什么不能将未压缩的TRIE(简称TRIE)称为Radix TRIE。
KGhatak '16

@ Seb-非常感谢您对Radix Tree 上stackoverflow.com/questions/40087385/…的反馈。副词adv。
KGhatak '16

@BuckCherry我很希望能够这样做,但是请意识到,由于我的计算机被盗,我将无法做出足够的响应。
自闭症

18

特里:
我们可以使用一种搜索方案,而不是将整个搜索键与所有现有键进行比较(例如哈希方案),还可以将搜索键的每个字符进行比较。按照这个想法,我们可以构建一个具有三个现有键的结构(如下所示):“ 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的影响。


2
作为根据Morrison,Sedgewick和Knuth实现PATRICIA的人,我可以告诉您,您在此处描述的算法(我也在尝试在答案中进行描述)仍然非常适合回答问题,例如列出与给定键匹配的所有键前缀。附注:很高兴看到其他人在球上:另一个问题:)我喜欢这种解释。
自闭症

关于“将不适合回答诸如列出与给定前缀匹配的所有键的问题”,认真吗?
Pacerier's

@Pacerier当然!经典PATRICIA存储一个整数,您可以将其用作数组的索引。将字符串放入数组中。在trie中,将字符串从0开始的数组索引。使搜索和比较以及位提取函数对与整数而不是整数相对应的字符串进行操作,并且如果您的插入函数是基于其他函数的(应该如此,因为那里有很多重复的逻辑),并且您一切都会好起来的。您还可以将其uintptr_t用作您的整数,因为似乎通常希望该类型(尽管不是必需的)存在。
自闭症

您声明“许多文献都仅将术语“基数基数”限制为压实的基数。” 实际上,除了维基百科,我找不到其他参考。你找到其他人了吗?
wds

@ wds-您可能是对的,因为我真的不记得我在撰写本文时所引用的资源是什么。快速搜寻可以让我找到链接,例如mathcs.emory.edu/~cheung/Courses/323/Syllabus/Text/trie02.htmltutorialsdiary.com/radix-trie-patricia-trie-or-compressed-trie,它们实际上指向或(最有可能)源自Wiki或受其影响。如果我发现任何其他可靠/学者的资源,请在此处发布。
KGhatak '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.