From d4e992c576a78943878dc5708f622399eee5809d Mon Sep 17 00:00:00 2001 From: chubbc <40682482+chubbc@users.noreply.github.com> Date: Wed, 17 Mar 2021 19:49:25 +0100 Subject: [PATCH 01/10] Include custom less-than in AVL Tree Allows one to pass a custom isless function to the AVLTree constructor, which is necessary when simply overloading isless is not possible due to scope issues. --- src/avl_tree.jl | 53 +++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index bacf1cbb2..a13f290a0 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -19,8 +19,9 @@ AVLTreeNode_or_null{T} = Union{AVLTreeNode{T}, Nothing} mutable struct AVLTree{T} root::AVLTreeNode_or_null{T} count::Int + lt - AVLTree{T}() where T = new{T}(nothing, 0) + AVLTree{T}(;lt=isless) where T = new{T}(nothing, 0, lt) end AVLTree() = AVLTree{Any}() @@ -58,7 +59,7 @@ end """ left_rotate(node_x::AVLTreeNode) -Performs a left-rotation on `node_x`, updates height of the nodes, and returns the rotated node. +Performs a left-rotation on `node_x`, updates height of the nodes, and returns the rotated node. """ function left_rotate(z::AVLTreeNode) y = z.rightChild @@ -75,7 +76,7 @@ end """ right_rotate(node_x::AVLTreeNode) -Performs a right-rotation on `node_x`, updates height of the nodes, and returns the rotated node. +Performs a right-rotation on `node_x`, updates height of the nodes, and returns the rotated node. """ function right_rotate(z::AVLTreeNode) y = z.leftChild @@ -90,9 +91,9 @@ function right_rotate(z::AVLTreeNode) end """ - minimum_node(tree::AVLTree, node::AVLTreeNode) + minimum_node(tree::AVLTree, node::AVLTreeNode) -Returns the AVLTreeNode with minimum value in subtree of `node`. +Returns the AVLTreeNode with minimum value in subtree of `node`. """ function minimum_node(node::Union{AVLTreeNode, Nothing}) while node != nothing && node.leftChild != nothing @@ -107,17 +108,17 @@ function search_node(tree::AVLTree{K}, d::K) where K while node != nothing && node.data != nothing && node.data != d prev = node - if d < node.data + if tree.lt(d,node.data) node = node.leftChild else node = node.rightChild end end - + return (node == nothing) ? prev : node end -function Base.haskey(tree::AVLTree{K}, d::K) where K +function Base.haskey(tree::AVLTree{K}, d::K) where K (tree.root == nothing) && return false node = search_node(tree, d) return (node.data == d) @@ -130,18 +131,18 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K function insert_node(node::Union{AVLTreeNode, Nothing}, key) if node == nothing return AVLTreeNode{K}(key) - elseif key < node.data + elseif tree.lt(key,node.data) node.leftChild = insert_node(node.leftChild, key) else node.rightChild = insert_node(node.rightChild, key) end - + node.subsize = compute_subtree_size(node) node.height = compute_height(node) balance = get_balance(node) - + if balance > 1 - if key < node.leftChild.data + if tree.lt(key,node.leftChild.data) return right_rotate(node) else node.leftChild = left_rotate(node.leftChild) @@ -150,7 +151,7 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K end if balance < -1 - if key > node.rightChild.data + if tree.lt(node.rightChild.data,key) return left_rotate(node) else node.rightChild = right_rotate(node.rightChild) @@ -176,9 +177,9 @@ end function Base.delete!(tree::AVLTree{K}, d::K) where K function delete_node!(node::Union{AVLTreeNode, Nothing}, key) - if key < node.data + if tree.lt(key,node.data) node.leftChild = delete_node!(node.leftChild, key) - elseif key > node.data + elseif tree.lt(node.data,key) node.rightChild = delete_node!(node.rightChild, key) else if node.leftChild == nothing @@ -187,13 +188,13 @@ function Base.delete!(tree::AVLTree{K}, d::K) where K elseif node.rightChild == nothing result = node.leftChild return result - else + else result = minimum_node(node.rightChild) node.data = result.data node.rightChild = delete_node!(node.rightChild, result.data) - end + end end - + node.subsize = compute_subtree_size(node) node.height = compute_height(node) balance = get_balance(node) @@ -214,14 +215,14 @@ function Base.delete!(tree::AVLTree{K}, d::K) where K node.rightChild = right_rotate(node.rightChild) return left_rotate(node) end - end - + end + return node end # if the key is not in the tree, do nothing and return the tree !haskey(tree, d) && return tree - + # if the key is present, delete it from the tree tree.root = delete_node!(tree.root, d) tree.count -= 1 @@ -238,18 +239,18 @@ function sorted_rank(tree::AVLTree{K}, key::K) where K node = tree.root rank = 0 while node.data != key - if (node.data < key) + if tree.lt(node.data, key) rank += (1 + get_subsize(node.leftChild)) node = node.rightChild else node = node.leftChild end - end + end rank += (1 + get_subsize(node.leftChild)) return rank end -function Base.getindex(tree::AVLTree{K}, ind::Integer) where K +function Base.getindex(tree::AVLTree{K}, ind::Integer) where K @boundscheck (1 <= ind <= tree.count) || throw(BoundsError("$ind should be in between 1 and $(tree.count)")) function traverse_tree(node::AVLTreeNode_or_null, idx) if (node != nothing) @@ -263,6 +264,6 @@ function Base.getindex(tree::AVLTree{K}, ind::Integer) where K end end end - value = traverse_tree(tree.root, ind) + value = traverse_tree(tree.root, ind) return value -end \ No newline at end of file +end From badc986bdd5a1b9fc446557c71aa1a89291a95a8 Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:51:09 +0100 Subject: [PATCH 02/10] Update src/avl_tree.jl Co-authored-by: Koustav Chowdhury --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index a13f290a0..eb76fd9c1 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -21,7 +21,7 @@ mutable struct AVLTree{T} count::Int lt - AVLTree{T}(;lt=isless) where T = new{T}(nothing, 0, lt) + AVLTree{T}(; lt = isless) where T = new{T}(nothing, 0, lt) end AVLTree() = AVLTree{Any}() From eeeb70e7a05f4805cc185883541c0cb3016fd6ec Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:51:21 +0100 Subject: [PATCH 03/10] Update src/avl_tree.jl Co-authored-by: Koustav Chowdhury --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index eb76fd9c1..85285adb1 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -108,7 +108,7 @@ function search_node(tree::AVLTree{K}, d::K) where K while node != nothing && node.data != nothing && node.data != d prev = node - if tree.lt(d,node.data) + if tree.lt(d, node.data) node = node.leftChild else node = node.rightChild From 14519e3c491f454ade9489f3bac93d9713eca3c9 Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:51:32 +0100 Subject: [PATCH 04/10] Update src/avl_tree.jl Co-authored-by: Koustav Chowdhury --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index 85285adb1..456374ac7 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -131,7 +131,7 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K function insert_node(node::Union{AVLTreeNode, Nothing}, key) if node == nothing return AVLTreeNode{K}(key) - elseif tree.lt(key,node.data) + elseif tree.lt(key, node.data) node.leftChild = insert_node(node.leftChild, key) else node.rightChild = insert_node(node.rightChild, key) From 95bd1da24d3724476327eca83ef78c798ea477ff Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:51:40 +0100 Subject: [PATCH 05/10] Update src/avl_tree.jl Co-authored-by: Koustav Chowdhury --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index 456374ac7..c1ea88852 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -142,7 +142,7 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K balance = get_balance(node) if balance > 1 - if tree.lt(key,node.leftChild.data) + if tree.lt(key, node.leftChild.data) return right_rotate(node) else node.leftChild = left_rotate(node.leftChild) From 332fbdf945a1a8aa14901ba005db13106033e4ce Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:51:48 +0100 Subject: [PATCH 06/10] Update src/avl_tree.jl Co-authored-by: Koustav Chowdhury --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index c1ea88852..6352f195a 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -151,7 +151,7 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K end if balance < -1 - if tree.lt(node.rightChild.data,key) + if tree.lt(node.rightChild.data, key) return left_rotate(node) else node.rightChild = right_rotate(node.rightChild) From e54030357fced0c124f4f4f5dac707d66035896e Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:52:02 +0100 Subject: [PATCH 07/10] Update src/avl_tree.jl Co-authored-by: Koustav Chowdhury --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index 6352f195a..bc285d145 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -177,7 +177,7 @@ end function Base.delete!(tree::AVLTree{K}, d::K) where K function delete_node!(node::Union{AVLTreeNode, Nothing}, key) - if tree.lt(key,node.data) + if tree.lt(key, node.data) node.leftChild = delete_node!(node.leftChild, key) elseif tree.lt(node.data,key) node.rightChild = delete_node!(node.rightChild, key) From bd6c82fc4d8db78c3d0d8d424710d29b1ced02cd Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:52:17 +0100 Subject: [PATCH 08/10] Update src/avl_tree.jl Co-authored-by: Koustav Chowdhury --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index bc285d145..9852bdcc7 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -179,7 +179,7 @@ function Base.delete!(tree::AVLTree{K}, d::K) where K function delete_node!(node::Union{AVLTreeNode, Nothing}, key) if tree.lt(key, node.data) node.leftChild = delete_node!(node.leftChild, key) - elseif tree.lt(node.data,key) + elseif tree.lt(node.data, key) node.rightChild = delete_node!(node.rightChild, key) else if node.leftChild == nothing From 1d5cc90d33b2254f904d4d52bcab270958e22bbe Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 19 Mar 2021 12:44:51 +0100 Subject: [PATCH 09/10] Update avl_tree.jl Define type of lt --- src/avl_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index 9852bdcc7..923a5aee7 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -19,7 +19,7 @@ AVLTreeNode_or_null{T} = Union{AVLTreeNode{T}, Nothing} mutable struct AVLTree{T} root::AVLTreeNode_or_null{T} count::Int - lt + lt::Function AVLTree{T}(; lt = isless) where T = new{T}(nothing, 0, lt) end From 319ef0dd509007c16fea5c405904de1e78df985a Mon Sep 17 00:00:00 2001 From: "Christopher T. Chubb" <40682482+chubbc@users.noreply.github.com> Date: Fri, 26 Mar 2021 13:00:49 +0100 Subject: [PATCH 10/10] Update avl_tree.jl Switch the specification of the ordering from an `lt` function to a `Base.Order.Ordering` --- src/avl_tree.jl | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/avl_tree.jl b/src/avl_tree.jl index 923a5aee7..e8aad8359 100644 --- a/src/avl_tree.jl +++ b/src/avl_tree.jl @@ -16,15 +16,19 @@ AVLTreeNode(d) = AVLTreeNode{Any}(d) AVLTreeNode_or_null{T} = Union{AVLTreeNode{T}, Nothing} -mutable struct AVLTree{T} +mutable struct AVLTree{T, Ord<:Ordering} root::AVLTreeNode_or_null{T} count::Int - lt::Function + ord::Ord - AVLTree{T}(; lt = isless) where T = new{T}(nothing, 0, lt) + AVLTree{T, Ord}(o::Ord=Forward) where {T, Ord<:Ordering} = new{T, Ord}(nothing, 0, o) end -AVLTree() = AVLTree{Any}() +AVLTree() = AVLTree{Any, ForwardOrdering}(Forward) + +AVLTree{T}() where T = AVLTree{T, ForwardOrdering}(Forward) + +AVLTree{T}(o::Ord) where {T, Ord<:Ordering} = AVLTree{T, Ord}(o) Base.length(tree::AVLTree) = tree.count @@ -105,10 +109,10 @@ end function search_node(tree::AVLTree{K}, d::K) where K prev = nothing node = tree.root - while node != nothing && node.data != nothing && node.data != d + while node != nothing && node.data != nothing && !eq(tree.ord, node.data, d) prev = node - if tree.lt(d, node.data) + if lt(tree.ord, d, node.data) node = node.leftChild else node = node.rightChild @@ -121,7 +125,7 @@ end function Base.haskey(tree::AVLTree{K}, d::K) where K (tree.root == nothing) && return false node = search_node(tree, d) - return (node.data == d) + return eq(tree.ord, node.data, d) end Base.in(key, tree::AVLTree) = haskey(tree, key) @@ -131,7 +135,7 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K function insert_node(node::Union{AVLTreeNode, Nothing}, key) if node == nothing return AVLTreeNode{K}(key) - elseif tree.lt(key, node.data) + elseif lt(tree.ord, key, node.data) node.leftChild = insert_node(node.leftChild, key) else node.rightChild = insert_node(node.rightChild, key) @@ -142,7 +146,7 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K balance = get_balance(node) if balance > 1 - if tree.lt(key, node.leftChild.data) + if lt(tree.ord, key, node.leftChild.data) return right_rotate(node) else node.leftChild = left_rotate(node.leftChild) @@ -151,7 +155,7 @@ function Base.insert!(tree::AVLTree{K}, d::K) where K end if balance < -1 - if tree.lt(node.rightChild.data, key) + if lt(tree.ord, node.rightChild.data, key) return left_rotate(node) else node.rightChild = right_rotate(node.rightChild) @@ -177,9 +181,9 @@ end function Base.delete!(tree::AVLTree{K}, d::K) where K function delete_node!(node::Union{AVLTreeNode, Nothing}, key) - if tree.lt(key, node.data) + if lt(tree.ord, key, node.data) node.leftChild = delete_node!(node.leftChild, key) - elseif tree.lt(node.data, key) + elseif lt(tree.ord, node.data, key) node.rightChild = delete_node!(node.rightChild, key) else if node.leftChild == nothing @@ -238,8 +242,8 @@ function sorted_rank(tree::AVLTree{K}, key::K) where K !haskey(tree, key) && throw(KeyError(key)) node = tree.root rank = 0 - while node.data != key - if tree.lt(node.data, key) + while !eq(tree.ord, node.data, key) + if lt(tree.ord, node.data, key) rank += (1 + get_subsize(node.leftChild)) node = node.rightChild else