Radix树结构

风杀数据结构约 1534 字大约 5 分钟

Radix树

Radix树,即基数树,也称压缩前缀树,是一种提供key-value存储查找的数据结构。与Trie不同的是,它对Trie树进行了空间优化,只有一个子节点的中间节点将被压缩。同样的,Radix树的插入、查询、删除操作的时间复杂度都为O(k)。

Radix树特点

一般由根节点、中间节点和叶子节点组成。

每个节点可以包含一个或多个字符。

树的叶子结点数即是数据条目数。

从根节点到某一节点经过路径的字符连起来即为该节点对应的字符串。

每个节点的所有子节点字符串都不相同。

插入操作

对romane、romanus、romulus、rubens、ruber、rubicon、rubicundus七个字符串进行插入,开始插入romane,此时树为空,直接创建一个“romane”节点,并将该节点结束标记设为true,随即完成romane的插入。

1afe99a453adc2b99bdbf7b05c24eb6d.jpg

接着插入romanus,此时根节点已经不为空,于是从根节点开始逐个字符进行比较,发现两者前缀“roman”相同,需要分割原来的“romane”节点,先创建一个新的公共前缀“roman”节点,

3d2422813c42cef77640670a63c5a5eb.jpg

然后将原来的“romane”节点设为“e”,“e”是“romane”除去公共前缀“roman”后剩下的字符,并将新的公共前缀节点指向“e”子节点,子节点索引为“e”。

28407373bbbb517190c2df2bed244804.jpg

接着继续创建一个新的“us”节点,“us”是“romanus”除去公共前缀“roman”后剩下的字符,

2caf92fe248ee665fcefc6c2a271578e.jpg

最后将公共前缀“roman”节点指向“us”子节点,索引为“u”,并将“us”节点结束标记设为true。

a2c3cf39293bef3c2d5361a8d782bb12.jpg

往下插入romulus,从根节点开始逐个字符进行比较,发现两者前缀“rom”相同,需要分割原来的“roman”节点,先创建一个新的公共前缀“rom”节点,

a5221d71a76706fc1867063b54a9f6f2.jpg

然后将原来的“roman”节点设为“an”,“an”是“roman”除去公共前缀“rom”后剩下的字符,并将新的公共前缀节点指向“an”子节点,子节点索引为“a”。

f70ba9f6c7c695f06ec7b9f80990278c.jpg

接着继续创建一个新的“ulus”节点,“ulus”是“romulus”除去公共前缀“rom”后剩下的字符,

0b6ebd791ef23a682f87ccfc530d93fd.jpg

最后将公共前缀“rom”节点指向“ulus”子节点,索引为“u”,并将“ulus”节点结束标记设为true。

6698af16977bd2872c898077843db61e.jpg

继续插入rubens,从根节点开始逐个字符进行比较,发现两者前缀“r”相同,需要分割原来的“rom”节点,先创建一个新的公共前缀“r”节点,

1016afe8fe3feb333da507395fdd4d4e.jpg

然后将原来的“rom”节点设为“om”,“om”是“rom”除去公共前缀“r”后剩下的字符,并将新的公共前缀节点指向“om”子节点,子节点索引为“o”。

63f98f6790a27bf5ff3260ff3e654833.jpg

接着继续创建一个新的“ubens”节点,“ubens”是“rubens”除去公共前缀“r”后剩下的字符,

0f85d44a422ccf60c898def02fb82420.jpg

最后将公共前缀“r”节点指向“ubens”子节点,索引为“u”,并将“ubens”节点结束标记设为true。

806c95ca607227630d565fd7b84eccaa.jpg

继续插入ruber,从根节点开始逐个字符进行比较,发现比较完“r”后根节点已经没有值可以比较了,于是开始找“r”节点的子节点,

0011dc7251399d5174c7d7a33c915bc5.jpg

根据第二个字符“u”找到对应的子节点,即“ubens”节点,

a26dc9ed4b5b259d4b7282303debee95.jpg

剩余的“uber”字符串继续与该节点进行逐一比较,发现两者前缀“ube”相同,需要分割原来的“ubens”节点,先创建一个新的公共前缀“ube”节点,

0fa8de1179615d675230db069df135a7.jpg

然后将原来的“ubens”节点设为“ns”,“ns”是“ubens”除去公共前缀“ube”后剩下的字符,并将新的公共前缀节点指向“ns”子节点,索引为“n”,此外,原来指向“ubens”节点的“u”索引指向“ube”节点。

93baacd92dad683b9ee5ebe47b431942.jpg

接着继续创建一个新的“r”节点,“r”是“ruber”除去公共前缀“r”和“ube”后剩下的字符,

d94d7f9e0dc0e8ffb118169338b0c3a4.jpg

最后将公共前缀“ube”节点指向“r”子节点,索引为“r”,并将“r”节点结束标记设为true。

cb3d4b0af4f3600b91dc81545b7f16d9.jpg

类似地,将rubicon插入树中,结果如下。

9fb8627cda51df5b2a047fc7defc28db.jpg

继续插入rubicundus,结果如下。

3973f7d25c97ec1430ef5a5d6fe184d5.jpg

查询操作

假如查找ruok,从根节点开始比较,“r”相等且根节点已经没有值可以继续比较,

3973f7d25c97ec1430ef5a5d6fe184d5.jpg

于是根据“u”索引找下一个子节点,在“ub”子节点中继续逐一字符比较,

48f8e725ffa8e47aba2866538da7d015.jpg

发现没法匹配上“uok”,不存在“ruok”,于是查找结束。假如查找rubicon,从根节点开始比较,“r”相等且根节点已经没有值可以继续比较,

ff39841c692d0e30cef735583a916604.jpg

于是根据“u”索引找下一个子节点,在“ub”子节点中继续逐一字符比较,

48f8e725ffa8e47aba2866538da7d015.jpg

比较完该节点后继续根据“i”索引找子节点,在“ic”节点中继续逐一字符比较,

538ba0cee61809ea2cd41e0c57156bbf.jpg

比较完该节点后继续根据“o”索引找子节点,在“on”节点中继续逐一字符比较,此时“rubicon”已经完成所有字符的比较,而且“on”节点的结束标记为true,也就是说存在“rubicon”字符串,查找结束。

0536742dadf89de9f010ae80908cc7b8.jpg

假如查找roman,从根节点开始比较,“r”相等且根节点已经没有值可以继续比较,

9e191cc16f17b88f8099a5df0ecbd002.jpg

于是根据“o”索引找下一个子节点,在“om”子节点中继续逐一字符比较,

89710211e7fa69adc4a26871e1238ee1.jpg

比较完该节点后继续根据“a”索引找子节点,在“an”节点中继续逐一字符比较,此时“roman”已经完成所有字符的比较,但“an”节点的结束标记为false,所以“roman”字符串不存在,查找结束。

c3b56541e1cc7db4a2919b92ad1df5e8.jpg

上次编辑于:
贡献者: 风杀