Red black tree sort/Wren
This is based, more or less, on the code here which I thought was reasonably intelligible.
Although red black trees don't necessarily need to disallow duplicate keys, I've adjusted the code to optionally disallow them. Not that it matters here as the method of constructing the random keys ensures that there will be no duplicates in any case.
import "random" for Random
/* Represents a node in the red-black tree. */
class Node {
// constructs a new node
construct new(data, parent, left, right, color) {
_data = data
_parent = parent
_left = left
_right = right
_color = color // 0 black, 1 red
}
// constructs a new 'sentinel' node
static new() { new(null, null, null, null, 0) }
data { _data }
parent { _parent }
left { _left }
right { _right }
color { _color }
data=(d) { _data = d }
parent=(p) { _parent = p }
left=(l) { _left = l }
right=(r) { _right = r }
color=(c) { _color = c }
}
/* Represents a red-black tree data structure. */
class RBTree {
// constructs a new red-black tree specifying whether duplicate keys are allowed or not
construct new(allowDups) {
_tnull = Node.new()
_root = _tnull
_allowDups = allowDups
}
// convenience version of the constructor which always allows duplicate keys
static new() { new(true) }
// returns the root node
root { _root }
/* private helper methods for basic operations */
preOrderHelper_(node) {
if (node != _tnull) {
System.print(node.data + " ")
preOrderHelper_(node.left)
preOrderHelper_(node.right)
}
}
inOrderHelper_(node) {
if (node != _tnull) {
inOrderHelper_(node.left)
System.print(node.data + " ")
inOrderHelper_(node.right)
}
}
postOrderHelper_(node) {
if (node != _tnull) {
postOrderHelper_(node.left)
postOrderHelper_(node.right)
System.print(node.data + " ")
}
}
searchTreeHelper_(node, key) {
if (node == _tnull || key == node.data) return node
if (key < node.data) return searchTreeHelper_(node.left, key)
return searchTreeHelper_(node.right, key)
}
fixDelete_(x) {
var s
while (x != _root && x.color == 0) {
if (x == x.parent.left) {
s = x.parent.right
if (s.color == 1) {
s.color = 0
x.parent.color = 1
leftRotate(x.parent)
s = x.parent.right
}
if (s.left.color == 0 && s.right.color == 0) {
s.color = 1
x = x.parent
} else {
if (s.right.color == 0) {
s.left.color = 0
s.color = 1
rightRotate(s)
s = x.parent.right
}
s.color = x.parent.color
x.parent.color = 0
s.right.color = 0
leftRotate(x.parent)
x = _root
}
} else {
s = x.parent.left
if (s.color == 1) {
s.color = 0
x.parent.color = 1
rightRotate(x.parent)
s = x.parent.left
}
if (s.left.color == 0 && s.right.color == 0) {
s.color = 1
x = x.parent
} else {
if (s.left.color == 0) {
s.right.color = 0
s.color = 1
leftRotate(s)
s = x.parent.left
}
s.color = x.parent.color
x.parent.color = 0
s.left.color = 0
rightRotate(x.parent)
x = _root
}
}
}
x.color = 0
}
rbTransplant_(u, v) {
if (!u.parent) {
_root = v
} else if (u == u.parent.left) {
u.parent.left = v
} else {
u.parent.right = v
}
v.parent = u.parent
}
deleteNodeHelper_(node, key) {
// find the node containing key
var z = _tnull
var x
var y
while (node != _tnull) {
if (node.data == key) z = node
if (node.data <= key) {
node = node.right
} else {
node = node.left
}
}
if (z == _tnull) {
System.print("Couldn't find key in the tree.")
return
}
y = z
var yOriginalColor = y.color
if (z.left == _tnull) {
x = z.right
rbTransplant_(z, z.right)
} else if (z.right == _tnull) {
x = z.left
rbTransplant_(z, z.left)
} else {
y = minimum(z.right)
yOriginalColor = y.color
x = y.right
if (y.parent == z) {
x.parent = y
} else {
rbTransplant_(y, y.right)
y.right = z.right
y.right.parent = y
}
rbTransplant_(z, y)
y.left = z.left
y.left.parent = y
y.color = z.color
}
if (yOriginalColor == 0) fixDelete_(x)
}
fixInsert_(k) {
var u
while (k.parent.color == 1) {
if (k.parent == k.parent.parent.right) {
u = k.parent.parent.left // uncle
if (u.color == 1) {
u.color = 0
k.parent.color = 0
k.parent.parent.color = 1
k = k.parent.parent
} else {
if (k == k.parent.left) {
k = k.parent
rightRotate(k)
}
k.parent.color = 0
k.parent.parent.color = 1
leftRotate(k.parent.parent)
}
} else {
u = k.parent.parent.right // uncle
if (u.color == 1) {
u.color = 0
k.parent.color = 0
k.parent.parent.color = 1
k = k.parent.parent
} else {
if (k == k.parent.right) {
k = k.parent
leftRotate(k)
}
k.parent.color = 0
k.parent.parent.color = 1
rightRotate(k.parent.parent)
}
}
if (k == _root) break
}
_root.color = 0
}
printHelper_(root, indent, last) {
if (root != _tnull) {
System.write(indent)
if (last) {
System.write("R----")
indent = indent + " "
} else {
System.write("L----")
indent = indent + "| "
}
var sColor = (root.color == 1) ? "RED" :"BLACK"
System.print(root.data.toString + "(" + sColor + ")")
printHelper_(root.left, indent, false)
printHelper_(root.right, indent, true)
}
}
/* public methods */
// check if a node with a given key already exists in the tree
hasKey(key) {
var node = searchTreeHelper_(_root, key)
return node.data == key
}
// pre-order traversal
// node.left subtree.right subtree
preOrder() { preOrderHelper_(_root) }
// in-order traversal
// left subtree . node . right subtree
inOrder() { inOrderHelper_(_root) }
// post-order traversal
// left subtree . right Subtree . node
postOrder() { postOrderHelper_(_root) }
// search the tree for the key k
// and return the corresponding node
searchTree(k) { searchTreeHelper_(_root, k) }
// find the node with the minimum key
minimum(node) {
while (node.left != _tnull) node = node.left
return node
}
// find the node with the maximum key
maximum(node) {
while (node.right != _tnull) node = node.right
return node
}
// find the successor of a given node
successor(x) {
// if the right subtree is not _tnull
// the successor is the leftmost node in the
// right subtree
if (x.right != _tnull) return minimum(x.right)
// else it is the lowest ancestor of x whose
// right child is also an ancestor of x.
var y = x.parent
while (y != _tnull && x == y.right) {
x = y
y = y.parent
}
return y
}
// find the predecessor of a given node
predecessor(x) {
// if the left subtree is not _tnull
// the predecessor is the rightmost node in the
// left subtree
if (x.left != _tnull) return maximum(x.left)
// else it is the lowest ancestor of x whose
// left child is also an ancestor of x.
var y = x.parent
while (y != _tnull && x == y.left) {
x = y
y = y.parent
}
}
// rotate left at node x
leftRotate(x) {
var y = x.right
x.right = y.left
if (y.left != _tnull) y.left.parent = x
y.parent = x.parent
if (!x.parent) {
_root = y
} else if (x == x.parent.left) {
x.parent.left = y
} else {
x.parent.right = y
}
y.left = x
x.parent = y
}
// rotate right at node x
rightRotate(x) {
var y = x.left
x.left = y.right
if (y.right != _tnull) y.right.parent = x
y.parent = x.parent
if (!x.parent) {
_root = y
} else if (x == x.parent.right) {
x.parent.right = y
} else {
x.parent.left = y
}
y.right = x
x.parent = y
}
// insert the key to the tree in its appropriate position
// and fix the tree
insert(key) {
// ordinary binary search insertion
var y = null
var x = _root
while (x != _tnull) {
y = x
if (key < x.data) {
x = x.left
} else {
x = x.right
}
}
// if duplicates aren't allowed and the key has already been used, simply return
if (!_allowDups && y && y.data == key) return
// new node must be red
var node = Node.new(key, null, _tnull, _tnull, 1)
// y is parent of x
node.parent = y
if (!y) {
_root = node
} else if (node.data < y.data) {
y.left = node
} else {
y.right = node
}
// if new node is a root node, simply return
if (!node.parent) {
node.color = 0
return
}
// if the grandparent is null, simply return
if (!node.parent.parent) return
// fix the tree
fixInsert_(node)
}
// delete the node from the tree
deleteNode(data) {
deleteNodeHelper_(_root, data)
}
// print the tree structure on the terminal
prettyPrint() {
printHelper_(_root, "", true)
}
}
var bst = RBTree.new(false) // disallow duplicates
var rand = Random.new()
// permit random keys from 1 to 99 say
var candidates = (1..99).toList
// shuffle them and insert the first 30 in the RBT
rand.shuffle(candidates)
var insertions = candidates[0..29]
for (k in insertions) bst.insert(k)
System.print("State of the tree after inserting the 30 keys:")
System.print(insertions)
System.print()
bst.prettyPrint()
// now delete 15 of them at random and redisplay the tree
rand.shuffle(insertions)
var deletions = insertions[0..14]
for (k in deletions) bst.deleteNode(k)
System.print("\nState of the tree after deleting the 15 keys:")
System.print(deletions)
System.print()
bst.prettyPrint()
- Output:
Sample output.
State of the tree after inserting the 30 keys: [85, 57, 51, 50, 86, 39, 95, 49, 44, 48, 21, 83, 11, 59, 88, 66, 4, 40, 24, 82, 63, 22, 37, 32, 91, 74, 28, 75, 62, 81] R----50(BLACK) L----39(RED) | L----21(BLACK) | | L----11(BLACK) | | | L----4(RED) | | R----24(RED) | | L----22(BLACK) | | R----32(BLACK) | | L----28(RED) | | R----37(RED) | R----44(BLACK) | L----40(BLACK) | R----49(BLACK) | L----48(RED) R----83(RED) L----66(BLACK) | L----57(RED) | | L----51(BLACK) | | R----62(BLACK) | | L----59(RED) | | R----63(RED) | R----75(RED) | L----74(BLACK) | R----82(BLACK) | L----81(RED) R----86(BLACK) L----85(BLACK) R----91(BLACK) L----88(RED) R----95(RED) State of the tree after deleting the 15 keys: [32, 40, 57, 63, 66, 75, 86, 59, 83, 51, 24, 62, 82, 39, 37] R----50(BLACK) L----28(RED) | L----21(BLACK) | | L----11(BLACK) | | | L----4(RED) | | R----22(BLACK) | R----48(BLACK) | L----44(BLACK) | R----49(BLACK) R----85(BLACK) L----81(BLACK) | L----74(RED) R----91(RED) L----88(BLACK) R----95(BLACK)