Skip to content
57 changes: 57 additions & 0 deletions src/binarytree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,60 @@ 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 prevnext(tree::BinaryTree, k)
prev, next = nothing, nothing
current = root(tree)
# traverse from the root to the target node, updating candidates
while !isnothing(current) && key(current) != k
if k < key(current)
# current is a potential next (successor)
next = current
current = left(current)
else # k > key(current)
# current is a potential previous (predecessor)
prev = current
current = right(current)
end
end

# if the node wasn't found, return the best candidate values
if isnothing(current)
return (prev, next)
end

# if there is a left subtree, the true previous (predecessor) is the maximum in that subtree
if !isnothing(left(current))
prev = maxnode(left(current))
end
# similarly, if there is a right subtree, the true next (successor) is the minimum in that subtree
if !isnothing(right(current))
next = minnode(right(current))
end

(prev, next)
end

prevnext(tree::BinaryTree, k::Nothing) = (nothing, nothing)
43 changes: 42 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,34 @@ 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.prevnext(tree, 0)[1] == nothing
@test BT.key.(BT.prevnext(tree, 2)) == (1, 3)
@test BT.key.(BT.prevnext(tree, 5)) == (4, 6)
@test BT.prevnext(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 Nothing BT.minnode(tree)
@inferred Nothing BT.maxnode(tree)
@inferred Tuple{Union{BT.AVLNode,Nothing},Union{BT.AVLNode,Nothing}} BT.prevnext(
tree,
2
)
@inferred BT.prevnext(tree, nothing)
@inferred Nothing BT.search(tree, 2)
@inferred Nothing BT.search(tree, 1)
@inferred Nothing BT.search(tree, 3)
Expand All @@ -234,6 +257,12 @@ const BT = BinaryTrees
@inferred BT.insert!(tree, 2)
@inferred BT.insert!(tree, 1)
@inferred BT.insert!(tree, 3)
@inferred Nothing BT.minnode(tree)
@inferred Nothing BT.maxnode(tree)
@inferred Tuple{Union{BT.AVLNode,Nothing},Union{BT.AVLNode,Nothing}} BT.prevnext(
tree,
2
)
@inferred Nothing BT.search(tree, 2)
@inferred Nothing BT.search(tree, 1)
@inferred Nothing BT.search(tree, 3)
Expand All @@ -244,6 +273,12 @@ const BT = BinaryTrees
@inferred BT.insert!(tree, "key2", 2)
@inferred BT.insert!(tree, "key1", 1)
@inferred BT.insert!(tree, "key3", 3)
@inferred Nothing BT.minnode(tree)
@inferred Nothing BT.maxnode(tree)
@inferred Tuple{Union{BT.AVLNode,Nothing},Union{BT.AVLNode,Nothing}} BT.prevnext(
tree,
"key2"
)
@inferred Nothing BT.search(tree, "key2")
@inferred Nothing BT.search(tree, "key1")
@inferred Nothing BT.search(tree, "key3")
Expand All @@ -254,6 +289,12 @@ const BT = BinaryTrees
@inferred BT.insert!(tree, (0, 1, 0), 2)
@inferred BT.insert!(tree, (0, 0, 1), 1)
@inferred BT.insert!(tree, (1, 0, 0), 3)
@inferred Nothing BT.minnode(tree)
@inferred Nothing BT.maxnode(tree)
@inferred Tuple{Union{BT.AVLNode,Nothing},Union{BT.AVLNode,Nothing}} BT.prevnext(
tree,
(0, 1, 0)
)
@inferred Nothing BT.search(tree, (0, 1, 0))
@inferred Nothing BT.search(tree, (0, 0, 1))
@inferred Nothing BT.search(tree, (1, 0, 0))
Expand Down