Skip to content
64 changes: 64 additions & 0 deletions src/binarytree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,67 @@ function _printkeyvalue(io::IO, node::BinaryNode)
show(ioctx, val)
end
end

# -----------
# UTILITIES
# -----------

minnode(tree::BinaryTree) = minnode(root(tree))

function minnode(node::BinaryNode)
leftnode = left(node)
isnothing(leftnode) ? node : minnode(leftnode)
end

minnode(node::Nothing) = nothing

maxnode(tree::BinaryTree) = maxnode(root(tree))

function maxnode(node::BinaryNode)
rightnode = right(node)
isnothing(rightnode) ? node : maxnode(rightnode)
end

maxnode(node::Nothing) = nothing

function abovebelow(tree::BinaryNode, x::BinaryNode)
above, below = nothing, nothing
current = tree
# Traverse from the root to the target node, updating candidates.
while !isnothing(current) && key(current) != key(x)
if key(x) < key(current)
# current is a potential above (successor)
above = current
current = left(current)
else # x.key > current.key
# current is a potential below (predecessor)
below = current
current = right(current)
end
end

# If the node wasn't found, return the best candidate values
if isnothing(current)
return (above, below)
end

# Found the node with key equal to x.key.
# Now, if there is a left subtree, the true below (predecessor) is the maximum in that subtree.
if !isnothing(left(current))
below = maxnode(left(current))
end
# Similarly, if there is a right subtree, the true above (successor) is the minimum in that subtree.
if !isnothing(right(current))
above = minnode(right(current))
end

(above, below)
end

function abovebelow(tree::BinaryTree, x::BinaryNode)
abovebelow(root(tree), x)
end

function abovebelow(tree, x::Nothing)
(nothing, nothing)
end
23 changes: 22 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const BT = BinaryTrees
BT.insert!(tree, 2, 20)
BT.insert!(tree, 1, 10)
BT.insert!(tree, 3, 30)
# deleting a key that does not exist
# deleting a key that does not exist
# does not change the tree
BT.delete!(tree, 4)
@test tree === tree
Expand Down Expand Up @@ -219,11 +219,32 @@ const BT = BinaryTrees
@test BT.value(BT.search(tree, (0, 0, 1))) == 1
@test BT.value(BT.search(tree, (1, 0, 0))) == 3

# traversal algorithms
tree = AVLTree{Int,Float64}()
BT.insert!(tree, 0, 5)
BT.insert!(tree, 1, 6)
BT.insert!(tree, 2, 8)
BT.insert!(tree, 3, 10)
BT.insert!(tree, 4, 20)
BT.insert!(tree, 5, 30)
BT.insert!(tree, 6, 40)
@test BT.key(BT.minnode(tree)) == 0
@test BT.key(BT.maxnode(tree)) == 6
@test BT.abovebelow(tree, BT.AVLNode(0, 5))[2] == nothing
@test BT.key.(BT.abovebelow(tree, BT.AVLNode(2, 10))) == (3, 1)
@test BT.key.(BT.abovebelow(BT.root(tree), BT.AVLNode(2, 10))) == (3, 1)
@test BT.key.(BT.abovebelow(tree, BT.AVLNode(5, 30))) == (6, 4)
@test BT.abovebelow(tree, nothing) == (nothing, nothing)
@test BT.abovebelow(BT.root(tree), nothing) == (nothing, nothing)

# type stability
tree = AVLTree{Int,Int}()
@inferred BT.insert!(tree, 2, 20)
@inferred BT.insert!(tree, 1, 10)
@inferred BT.insert!(tree, 3, 30)
@inferred BT.minnode(tree)
@inferred BT.maxnode(tree)
@inferred BT.abovebelow(tree, BT.AVLNode(2, 20))
@inferred Nothing BT.search(tree, 2)
@inferred Nothing BT.search(tree, 1)
@inferred Nothing BT.search(tree, 3)
Expand Down
Loading