rbt: fix rbtree deletion

This commit is contained in:
c9s 2021-06-07 00:48:23 +08:00
parent 103b1ea560
commit 06bf0d0f2b
2 changed files with 28 additions and 21 deletions

View File

@ -27,26 +27,37 @@ func NewRBTree() *RBTree {
} }
func (tree *RBTree) Delete(key fixedpoint.Value) bool { func (tree *RBTree) Delete(key fixedpoint.Value) bool {
var del = tree.Search(key) var deleting = tree.Search(key)
if del == nil { if deleting == nil {
return false return false
} }
// y = the node to be deleted // y = the node to be deleted
// x (the child of the deleted node) // x (the child of the deleted node)
var x, y *RBNode var x, y *RBNode
// fmt.Printf("neel = %p %+v\n", tree.neel, tree.neel)
// fmt.Printf("deleting = %+v\n", deleting)
if del.Left == tree.neel || del.Right == tree.neel { // the deleting node has only one child, it's easy,
y = del // we just connect the child the parent of the deleting node
if deleting.Left == tree.neel || deleting.Right == tree.neel {
y = deleting
// fmt.Printf("y = deleting = %+v\n", y)
} else { } else {
y = tree.Successor(del) // if both children are not NIL (neel), we need to find the successor
// and copy the successor to the memory location of the deleting node.
// since it's successor, it always has no child connecting to it.
y = tree.Successor(deleting)
// fmt.Printf("y = successor = %+v\n", y)
} }
// y.Left or y.Right could be neel
if y.Left != tree.neel { if y.Left != tree.neel {
x = y.Left x = y.Left
} else { } else {
x = y.Right x = y.Right
} }
// fmt.Printf("x = %+v\n", y)
x.Parent = y.Parent x.Parent = y.Parent
@ -58,12 +69,14 @@ func (tree *RBTree) Delete(key fixedpoint.Value) bool {
y.Parent.Right = x y.Parent.Right = x
} }
if y != del { if y != deleting {
del.Key = y.Key deleting.Key = y.Key
} }
if y.Color == Black { if y.Color == Black {
tree.DeleteFixup(x) if x != nil {
tree.DeleteFixup(x)
}
} }
tree.size-- tree.size--
@ -216,7 +229,7 @@ func (tree *RBTree) Insert(key, val fixedpoint.Value) {
func (tree *RBTree) Search(key fixedpoint.Value) *RBNode { func (tree *RBTree) Search(key fixedpoint.Value) *RBNode {
var current = tree.Root var current = tree.Root
for current != tree.neel && key != current.Key { for current != nil && key != current.Key {
if key < current.Key { if key < current.Key {
current = current.Left current = current.Left
} else { } else {
@ -224,11 +237,6 @@ func (tree *RBTree) Search(key fixedpoint.Value) *RBNode {
} }
} }
// convert Neel to real nil
if current == tree.neel {
return nil
}
return current return current
} }
@ -335,7 +343,7 @@ func (tree *RBTree) Rightmost() *RBNode {
} }
func (tree *RBTree) RightmostOf(current *RBNode) *RBNode { func (tree *RBTree) RightmostOf(current *RBNode) *RBNode {
for current.Right != nil { for current.Right != tree.neel {
current = current.Right current = current.Right
} }
@ -347,7 +355,7 @@ func (tree *RBTree) Leftmost() *RBNode {
} }
func (tree *RBTree) LeftmostOf(current *RBNode) *RBNode { func (tree *RBTree) LeftmostOf(current *RBNode) *RBNode {
for current.Left != nil { for current.Left != tree.neel {
current = current.Left current = current.Left
} }
@ -355,12 +363,12 @@ func (tree *RBTree) LeftmostOf(current *RBNode) *RBNode {
} }
func (tree *RBTree) Successor(current *RBNode) *RBNode { func (tree *RBTree) Successor(current *RBNode) *RBNode {
if current.Right != nil { if current.Right != tree.neel {
return tree.LeftmostOf(current.Right) return tree.LeftmostOf(current.Right)
} }
var newNode = current.Parent var newNode = current.Parent
for newNode != nil && current == newNode.Right { for newNode != tree.neel && current == newNode.Right {
current = newNode current = newNode
newNode = newNode.Parent newNode = newNode.Parent
} }

View File

@ -12,8 +12,8 @@ func TestTree_InsertAndDelete(t *testing.T) {
var keys []fixedpoint.Value var keys []fixedpoint.Value
tree := NewRBTree() tree := NewRBTree()
for i := 1; i < 10.0; i++ { for i := 1; i < 100; i++ {
v := fixedpoint.NewFromFloat(rand.Float64()) v := fixedpoint.NewFromFloat(rand.Float64() * 100 + 1.0)
keys = append(keys, v) keys = append(keys, v)
tree.Insert(v, fixedpoint.NewFromFloat(float64(i))) tree.Insert(v, fixedpoint.NewFromFloat(float64(i)))
} }
@ -22,7 +22,6 @@ func TestTree_InsertAndDelete(t *testing.T) {
ok := tree.Delete(key) ok := tree.Delete(key)
assert.True(t, ok, "should find and delete the node") assert.True(t, ok, "should find and delete the node")
} }
} }
func TestTree_CopyInorder(t *testing.T) { func TestTree_CopyInorder(t *testing.T) {