为什么Clojure Cookbook中的红黑树错过了重新加工的案例

时间:2014-04-01 08:56:13

标签: data-structures clojure tree red-black-tree

在使用Clojure Cookbook中的Red-Black Tree实现示例后,我注意到平衡功能不包含重新着色的情况。 (大多数红黑树文献中的案例1,或者也称为插入节点的叔叔为红色的情况)。

(defn balance
  "Ensures the given subtree stays balanced by rearranging black nodes
  that have at least one red child and one red grandchild"
  [tree]
  (match [tree]
         [(:or ;; Left child red with left red grandchild
               [:black [:red [:red a x b] y c] z d]
               ;; Left child red with right red grandchild
               [:black [:red a x [:red b y c]] z d]
               ;; Right child red with left red grandchild
               [:black a x [:red [:red b y c] z d]]
               ;; Right child red with right red grandchild
               [:black a x [:red b y [:red c z d]]])] [:red [:black a x b]
                                                            y
                                                            [:black c z d]]
               :else tree))

这是一个小例子:

在我看来,在树8中插入数字a可以通过重新着色第二级来生成树b。 Clojure Cookbook中的实现不必要地旋转树,生成树c

Red-Black-Trees

是否有充分理由在实施中忽略此案例?

2 个答案:

答案 0 :(得分:7)

我是这个特殊食谱的作者。

大多数红黑树实现和教科书都假设一个可变的上下文,您可以在其中就地更新特定节点。在这种情况下,更改节点的颜色肯定比树旋转更便宜。

然而,Clojure Book实现纯粹是功能性的,意味着没有突变。因此,无论您是重新加载节点还是创建新子树,成本都是相同的,因为我们无论如何都要复制节点。因此我们顺其自然。这样可以使平衡功能尽可能简单,同时保持所有红黑属性。

这项实施的灵感来自Chris Okasaki的书Purely Functional Data Structures。对于任何对持久性数据结构感兴趣的人,我都会推荐它。

答案 1 :(得分:1)

纯粹的功能设置中,不能改变节点的颜色。重新着色而不是旋转可以在命令式实现中保存一些指针赋值,但在功能性实现中,您必须创建所需颜色的新节点,并且无论如何都要在构造中为父级中的子节点进行分配。您还会注意到此实现比传统的命令式版本更简单。