赤黒木 (14)

朝練メモ。ここから順に 2 と -1 な要素が削除される模様。

  ;;          B:-1.5 => -1.5
  ;;        R:-1 => -1
  ;;          B:-0.5 => -0.5
  ;;      B:0 => 0
  ;;        B:1 => 1
  ;;    B:2 => 2
  ;;        B:2.5 => 2.5
  ;;      B:3 => 3
  ;;        B:3.5 => 3.5
  ;;          R:4 => 4

以下なコメントがあります。

  ;;   case 3.  this goes through parent==NULL stop condition in the
  ;;            loop in delete_node1.

確かに key が 2 な要素は root になっています。順に確認を。
delete-node! 手続きから

  (let1 z (if (and (not (nil? (left z))) (not (nil? (right z))))
            (let1 y (successor z)
              (set! (ref z 'key) (ref y 'key))
              (set! (ref z 'value) (ref y 'value))
              y)
            z)

む、今回は z の左右の子供は nil ではないですね。ええと successor は次に大きい key の要素を戻すはずなので、key が 2.5 な要素を戻すのか。z がそれにおきかわるのかな。あ、z の key と value も置き換えられるのか。あー、入れ替えて元あった方を削除するのか。

    (let ((x (left* z (not (nil? (left z)))))
          (p (parent z)))

x には nil、p は key が 3 の要素、になるのかどうか。

      (unless (nil? x)
        (set! (parent x) p))

x が nil なのでここはスルー。

      (if (nil? p)
        (set! (root-of tree) x)
        (set! (left* p (eq? z (left p))) x))

p は nil ではないので、key が 3 の左の子供な key が 2.5 な要素は切り離し。

      (when (black? z)
        (delete-fixup! tree x p))

z は黒なので delete-fixup! 呼び出されます。この時点での tree は以下?

  ;;          B:-1.5 => -1.5
  ;;        R:-1 => -1
  ;;          B:-0.5 => -0.5
  ;;      B:0 => 0
  ;;        B:1 => 1
  ;;    B:2.5 => 2.5
  ;;      B:3 => 3
  ;;        B:3.5 => 3.5
  ;;          R:4 => 4

引数な x は nil で p は key が 3 な要素を指してます。

  (let loop ((x x) (p p))
    (if (or (nil? p) (red? x))
      (unless (nil? x)
        (paint-black! x))

p は nil でなく、x も黒 (nil) なのでここはスルー。

      (let1 b (eq? x (left p))
        (let1 w (let1 w (right* p b)
                  (if (red? w)
                    (begin (paint-black! w)
                           (paint-red! p)
                           (left-rotate! tree p b)
                           (right* p b))
                    w))

b は #t ですね。p の右は key が 3.5 の要素で黒なので w はこの要素を指します。

          (if (and (black? (left w)) (black? (right w)))
            (begin (paint-red! w)
                   (loop p (parent p)))

w の右側の子供は赤なのでここもスルー。

            (let1 w (if (black? (right* w b))
                      (begin (unless (nil? (left* w b))
                               (paint-black! (left* w b)))
                             (paint-red! w)
                             (right-rotate! tree w b)
                             (right* p b))
                      w)

右側の子供は赤なのでここもスルーで w は key が 3.5 の要素を指したまま。

              (set! (ref w 'color)
                    (if (nil? p) 'black (ref p 'color)))
              (paint-black! p)
              (paint-black! (right* w b))
              (left-rotate! tree p b)
              (paint-black! (root-of tree)))))))))
  • w の色は p の色に、ですが両方黒なので変わらず
  • p を黒に
  • w の右を黒に、なので key が 4 の要素は黒になります

で、left-rotate! 呼び出し前の tree が以下になるのか。

  ;;          B:-1.5 => -1.5
  ;;        R:-1 => -1
  ;;          B:-0.5 => -0.5
  ;;      B:0 => 0
  ;;        B:1 => 1
  ;;    B:2.5 => 2.5
  ;;      B:3 => 3
  ;;        B:3.5 => 3.5
  ;;          B:4 => 4

p は key が 3 の要素を指してる状態で b は #t か。

  (let1 y (right* x b)

y は key が 3.5 の要素を指す。

    (set! (right* x b) (left* y b))
    (unless (nil? (left* y b))
      (set! (parent (left* y b)) x))

ええと、これって

  ;;    B:2.5 => 2.5
  ;;      B:3 => 3
  ;;        B:3.5 => 3.5
  ;;          B:4 => 4

  ;;    B:2.5 => 2.5
  ;;        B:3 => 3
  ;;      B:3.5 => 3.5
  ;;        B:4 => 4

てなるんだっけ。とりあえず y は x の右から切り離されてます。

    (set! (parent y) (parent x))

で、y の親は x の親に。key が 3.5 の親は key が 2.5 の要素になりますね。

    (cond ((nil? (parent x))
           (set! (root-of tree) y))
          ((eq? x (left* (parent x) b))
           (set! (left* (parent x) b) y))
          (else
           (set! (right* (parent x) b) y)))

x はその親の右側要素なので、ということで親からのリンクを張り直しています。

    (set! (left* y b) x)
    (set! (parent x) y)))

で、x を y の左にして終了。こうなりました。

  ;;          B:-1.5 => -1.5
  ;;        R:-1 => -1
  ;;          B:-0.5 => -0.5
  ;;      B:0 => 0
  ;;        B:1 => 1
  ;;    B:2.5 => 2.5
  ;;        B:3 => 3
  ;;      B:3.5 => 3.5
  ;;        B:4 => 4

これで 2 の削除が終了。次が -1 な要素の削除になりますが、タイムアップ。