【发布时间】:2026-01-09 19:55:01
【问题描述】:
我正在尝试实现一棵红黑树。我有插入工作,并且在过去的几天里一直试图让删除工作。我为糟糕的变量名称道歉;我将它们更改为通用的“x、y、w、z”名称,以适当地将我的代码与 CLRS 伪代码进行比较。到目前为止,这是我的代码:
// Delete takes a key, removes the node from the tree, and decrements the size of the tree.
// The function returns the key of the deleted node and an error, if there was one.
func (tree *RBT) Delete(key interface{}) (interface{}, error) {
z, err := tree.findNode(key)
// node with key does not exist
if err != nil {
return nil, err
}
nodeToDeleteKey := z.key()
y := z
originalColor := y.getColor()
var x *Node
if z.leftChild() == nil {
x = z.rightChild()
tree.replaceSubTree(z, z.rightChild())
} else if z.rightChild() == nil {
x = z.leftChild()
tree.replaceSubTree(z, z.leftChild())
} else {
y = z.rightChild().subtreeMin()
originalColor = y.getColor()
x = y.rightChild()
if y.getParent() == z {
x.setParent(y)
} else {
tree.replaceSubTree(y, y.rightChild())
y.setRightChild(z.rightChild())
y.rightChild().setParent(y)
}
tree.replaceSubTree(z, y)
y.setLeftChild(z.leftChild())
y.leftChild().setParent(y)
y.setColor(z.getColor())
}
if originalColor == BLACK {
tree.deleteFixup(x)
}
tree.setSize(tree.Size() - 1)
return nodeToDeleteKey, nil
}
// replaceSubTree replaces one subtree as a child of its parent with
// another subtree. When replaceSubTree replaces the subtree rooted at node u with
// the subtree rooted at node v, node u’s parent becomes node v’s parent, and u’s
// parent ends up having as its appropriate child.
func (tree *RBT) replaceSubTree(toDelete *Node, replacement *Node) {
switch {
case toDelete == tree.Root():
tree.setRoot(replacement)
case toDelete == toDelete.getParent().leftChild(): // node to delete is left child
toDelete.getParent().setLeftChild(replacement)
default: // node to delete is right child
toDelete.getParent().setRightChild(replacement)
}
replacement.setParent(toDelete.getParent())
}
// deleteFixup maintains the invariants of the red-black tree after deletion.
func (tree *RBT) deleteFixup(x *Node) {
for x != tree.Root() && x.getColor() == BLACK {
switch {
case x == x.getParent().leftChild():
w := x.getParent().rightChild()
if w.getColor() == RED {
w.recolor()
x.getParent().setColor(RED)
tree.leftRotate(x.getParent())
w = x.getParent().rightChild()
}
if w.leftChild().getColor() == BLACK && w.rightChild().getColor() == BLACK {
w.setColor(RED)
x = x.getParent()
} else {
if w.rightChild().getColor() == BLACK {
w.leftChild().setColor(BLACK)
w.setColor(RED)
tree.rightRotate(w)
w = x.getParent().rightChild()
}
w.setColor(x.getParent().getColor())
x.getParent().setColor(BLACK)
w.rightChild().setColor(BLACK)
tree.leftRotate(x.getParent())
x = tree.Root()
}
default:
w := x.getParent().leftChild()
if w.getColor() == RED {
w.recolor()
x.getParent().setColor(RED)
tree.rightRotate(x.getParent())
w = x.getParent().leftChild()
}
if w.rightChild().getColor() == BLACK && w.leftChild().getColor() == BLACK {
w.setColor(RED)
x = x.getParent()
} else {
if w.leftChild().getColor() == BLACK {
w.rightChild().setColor(BLACK)
w.setColor(RED)
tree.leftRotate(w)
w = x.getParent().leftChild()
}
w.setColor(x.getParent().getColor())
x.getParent().setColor(BLACK)
w.leftChild().setColor(BLACK)
tree.rightRotate(x.getParent())
x = tree.Root()
}
}
}
x.setColor(BLACK)
}
我遇到了一个问题,我在 deleteFixup() 中遇到了无限循环。我有attached a screenshot of debugging that shows current variable values in deleteFixup。
当我将一个 nil 节点 (x) 传递给 deleteFixup() 时,就会出现问题...我相信它是在 Delete() 中的 if/else 条件下,其中 x 被分配给 nil:
if z.leftChild() == nil {
x = z.rightChild()
tree.replaceSubTree(z, z.rightChild())
} else if z.rightChild() == nil {
x = z.leftChild()
tree.replaceSubTree(z, z.leftChild())
}
if / else if 检查要删除的 (z) 左右子节点的节点以及它们是否为空。但有时,要删除的 (z) 右 和 左子节点都为空,并且 x 无论如何都会设置为空值。因此,当我将 x 传递给 deleteFixup() 时,循环永远不会中断,我会陷入以下逻辑:
if w.leftChild().getColor() == BLACK && w.rightChild().getColor() == BLACK {
w.setColor(RED)
x = x.getParent()
}
谁能帮我找出我的代码哪里出错了?谢谢!
【问题讨论】:
-
你没有展示函数 getColor() ,这很重要
标签: go debugging tree red-black-tree