Skip to content

Commit aedbb0b

Browse files
committed
Add functions, modify testset, address review
1 parent fe1ebd9 commit aedbb0b

File tree

3 files changed

+172
-75
lines changed

3 files changed

+172
-75
lines changed

src/DataStructures.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ module DataStructures
112112
export SparseIntSet
113113

114114
include("dibit_vector.jl")
115+
include("red_black_tree.jl")
115116
include("deprecations.jl")
116117

117-
include("red_black_tree.jl")
118118
end

src/red_black_tree.jl

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# it has unique keys
22
# leftChild has keys which are less than the node
33
# rightChild has keys which are greater than the node
4-
# color is true if it's a Red Node, else it's false
4+
# color is true if its a Red Node, else its false
55
mutable struct RBTreeNode{K}
66
color::Bool
77
data::Union{K, Nothing}
@@ -17,14 +17,6 @@ end
1717
RBTreeNode() = RBTreeNode{Any}()
1818
RBTreeNode(d) = RBTreeNode{Any}(d)
1919

20-
function Base.isequal(x::RBTreeNode{K}, y::RBTreeNode{K})where K
21-
return (x.color == y.color && x.data == y.data)
22-
end
23-
24-
Base.:(==)(x::RBTreeNode{K}, y::RBTreeNode{K}) where K = isequal(x, y)
25-
26-
Base.hash(x::RBTreeNode) = hash(x.data, hash(x.color))
27-
2820
function create_null_node(K::Type)
2921
node = RBTreeNode{K}()
3022
node.color = false
@@ -34,14 +26,21 @@ end
3426
mutable struct RBTree{K}
3527
root::RBTreeNode{K}
3628
nil::RBTreeNode{K}
29+
count::Int
3730

3831
function RBTree{K}() where K
39-
new{K}(create_null_node(K), create_null_node(K))
32+
rb = new()
33+
rb.nil = create_null_node(K)
34+
rb.root = Ref(rb.nil)[]
35+
rb.count = 0
36+
return rb
4037
end
4138
end
4239

4340
RBTree() = RBTree{Any}()
4441

42+
Base.length(tree::RBTree) = tree.count
43+
4544
"""
4645
search_node(tree, key)
4746
@@ -62,13 +61,13 @@ function search_node(tree::RBTree{K}, d::K) where K
6261
end
6362

6463
"""
65-
search_key(tree, key)
64+
haskey(tree, key)
6665
6766
Returns true if `key` is present in the `tree`, else returns false.
6867
"""
69-
search_key(tree, key)
68+
haskey(tree, key)
7069

71-
function search_key(tree::RBTree{K}, d::K) where K
70+
function Base.haskey(tree::RBTree{K}, d::K) where K
7271
node = search_node(tree, d)
7372
return (node.data == d)
7473
end
@@ -171,11 +170,11 @@ function fix_insert!(tree::RBTree, node::RBTreeNode)
171170
uncle.color = false
172171
node = grand_parent
173172
else # uncle is black in color
174-
if (node == parent.rightChild) # node is rightChild of it's parent
173+
if (node == parent.rightChild) # node is rightChild of its parent
175174
node = parent
176175
left_rotate!(tree, node)
177176
end
178-
# node is leftChild of it's parent
177+
# node is leftChild of its parent
179178
node.parent.color = false
180179
node.parent.parent.color = true
181180
right_rotate!(tree, node.parent.parent)
@@ -189,11 +188,11 @@ function fix_insert!(tree::RBTree, node::RBTreeNode)
189188
uncle.color = false
190189
node = grand_parent
191190
else # uncle is black in color
192-
if (node == parent.leftChild) # node is leftChild of it's parent
191+
if (node == parent.leftChild) # node is leftChild of its parent
193192
node = parent
194193
right_rotate!(tree, node)
195194
end
196-
# node is rightChild of it's parent
195+
# node is rightChild of its parent
197196
node.parent.color = false
198197
node.parent.parent.color = true
199198
left_rotate!(tree, node.parent.parent)
@@ -212,8 +211,8 @@ insert!(tree, key)
212211

213212
function Base.insert!(tree::RBTree{K}, d::K) where K
214213
# if the key exists in the tree, no need to insert
215-
search_key(tree, d) && return tree
216-
# search_key(tree, d) && return tree
214+
haskey(tree, d) && return tree
215+
217216
# insert, if not present in the tree
218217
node = RBTreeNode{K}(d)
219218
node.leftChild = node.rightChild = tree.nil
@@ -227,9 +226,20 @@ function Base.insert!(tree::RBTree{K}, d::K) where K
227226
else
228227
fix_insert!(tree, node)
229228
end
229+
tree.count += 1
230230
return tree
231231
end
232232

233+
"""
234+
insert!(tree, key)
235+
236+
Inserts `key` in the `tree` if it is not present.
237+
"""
238+
function Base.push!(tree::RBTree{K}, key0) where K
239+
key = convert(K, key0)
240+
insert!(tree, key)
241+
end
242+
233243
"""
234244
delete_fix(tree::RBTree, node::Union{RBTreeNode, Nothing})
235245
@@ -317,6 +327,7 @@ end
317327
Returns the RBTreeNode with minimum value in subtree of `node`.
318328
"""
319329
function minimum_node(tree::RBTree, node::RBTreeNode)
330+
(node == tree.nil) && return node
320331
while node.leftChild != tree.nil
321332
node = node.leftChild
322333
end
@@ -326,7 +337,7 @@ end
326337
"""
327338
delete!(tree::RBTree, key)
328339
329-
Deletes `key` from `tree`, if present, else throws a KeyError.
340+
Deletes `key` from `tree`, if present, else returns the unmodified tree.
330341
"""
331342
delete!(tree, key)
332343

@@ -346,7 +357,7 @@ function Base.delete!(tree::RBTree{K}, d::K) where K
346357
end
347358
end
348359

349-
(z == tree.nil) && throw(KeyError(d))
360+
(z == tree.nil) && return tree
350361

351362
y = z
352363
y_original_color = y.color
@@ -377,4 +388,30 @@ function Base.delete!(tree::RBTree{K}, d::K) where K
377388
end
378389

379390
!y_original_color && delete_fix(tree, x)
380-
end
391+
tree.count -= 1
392+
return tree
393+
end
394+
395+
Base.in(key, tree::RBTree) = haskey(tree, key)
396+
397+
"""
398+
getindex(tree, ind)
399+
400+
Gets the key present at index `ind` of the tree. Indexing is done in increasing order of key.
401+
"""
402+
getindex(tree, ind)
403+
404+
function Base.getindex(tree::RBTree{K}, ind) where K
405+
@boundscheck (1 <= ind <= tree.count) || throw(ArgumentError("$ind should be in between 1 and $(tree.count)"))
406+
function traverse_tree_inorder(node::RBTreeNode{K}) where K
407+
if (node != tree.nil)
408+
left = traverse_tree_inorder(node.leftChild)
409+
right = traverse_tree_inorder(node.rightChild)
410+
append!(push!(left, node.data), right)
411+
else
412+
return K[]
413+
end
414+
end
415+
arr = traverse_tree_inorder(tree.root)
416+
return @inbounds arr[ind]
417+
end

test/test_red_black_tree.jl

Lines changed: 112 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,137 @@
11
include("../src/red_black_tree.jl")
22
@testset "RBTree" begin
3-
t = RBTree{Int}()
4-
for i = 1:10000
5-
insert!(t, i)
6-
end
7-
for i = 1:10000
8-
@test search_key(t, i)
9-
end
3+
@testset "inserting values" begin
4+
t = RBTree{Int}()
5+
for i in 1:100
6+
insert!(t, i)
7+
end
108

11-
for i = 10001:20000
12-
@test !search_key(t, i)
13-
end
9+
@test length(t) == 100
1410

15-
for i = 1:2:10000
16-
delete!(t, i)
17-
end
11+
for i in 1:100
12+
@test haskey(t, i)
13+
end
1814

19-
for i = 1:10000
20-
if iseven(i)
21-
@test search_key(t, i)
22-
else
23-
@test !search_key(t, i)
24-
@test_throws KeyError delete!(t, i)
15+
for i = 101:200
16+
@test !haskey(t, i)
2517
end
2618
end
2719

28-
for i = 1:2:1000
29-
insert!(t, i)
20+
@testset "deleting values" begin
21+
t = RBTree{Int}()
22+
for i in 1:100
23+
insert!(t, i)
24+
end
25+
for i in 1:2:100
26+
delete!(t, i)
27+
end
28+
29+
@test length(t) == 50
30+
31+
for i in 1:100
32+
if iseven(i)
33+
@test haskey(t, i)
34+
else
35+
@test !haskey(t, i)
36+
end
37+
end
38+
39+
for i in 1:2:100
40+
insert!(t, i)
41+
end
42+
43+
@test length(t) == 100
44+
3045
end
3146

32-
for i = 1:1000
33-
@test search_key(t, i)
47+
@testset "handling different cases of delete!" begin
48+
t2 = RBTree()
49+
for i in 1:100000
50+
insert!(t2, i)
51+
end
52+
53+
@test length(t2) == 100000
54+
55+
nums = rand(1:100000, 8599)
56+
visited = Set()
57+
for num in nums
58+
if !(num in visited)
59+
delete!(t2, num)
60+
push!(visited, num)
61+
end
62+
end
63+
64+
for i in visited
65+
@test !haskey(t2, i)
66+
end
67+
@test (length(t2) + length(visited)) == 100000
3468
end
3569

36-
# test hash
37-
for i = 1:1000
38-
node = search_node(t, i)
39-
@test hash(node) == hash(i, hash(node.color))
70+
@testset "handling different cases of insert!" begin
71+
nums = rand(1:100000, 1000)
72+
t3 = RBTree()
73+
uniq_nums = Set(nums)
74+
for num in nums
75+
insert!(t3, num)
76+
end
77+
@test length(t3) == length(uniq_nums)
4078
end
4179

42-
# for handling cases related to delete!
43-
t2 = RBTree()
44-
for i = 1:100000
45-
insert!(t2, i)
80+
@testset "in" begin
81+
t4 = RBTree{Char}()
82+
push!(t4, 'a')
83+
push!(t4, 'b')
84+
@test length(t4) == 2
85+
@test in('a', t4)
86+
@test !in('c', t4)
4687
end
4788

48-
nums = rand(1:100000, 1000)
49-
visited = Set()
50-
for num in nums
51-
if num in visited
52-
@test_throws KeyError delete!(t2, num)
53-
else
54-
delete!(t2, num)
55-
push!(visited, num)
89+
@testset "search_node" begin
90+
t5 = RBTree()
91+
for i in 1:32
92+
push!(t5, i)
5693
end
57-
end
94+
n1 = search_node(t5, 21)
95+
@test n1.data == 21
96+
n2 = search_node(t5, 35)
97+
@test n2 === t5.nil
98+
n3 = search_node(t5, 0)
99+
@test n3 === t5.nil
100+
end
58101

59-
for i = 1:100000
60-
if i in visited
61-
@test !search_key(t2, i)
62-
else
63-
@test search_key(t2, i)
102+
@testset "getindex" begin
103+
t6 = RBTree{Int}()
104+
for i in 1:10
105+
push!(t6, i)
106+
end
107+
for i in 1:10
108+
@test getindex(t6, i) == i
64109
end
110+
@test_throws ArgumentError getindex(t6, 0)
111+
@test_throws ArgumentError getindex(t6, 11)
65112
end
66113

67-
# for handling cases related to insert!
68-
t3 = RBTree()
69-
for num in nums
70-
insert!(t3, num)
114+
@testset "key conversion in push!" begin
115+
t7 = RBTree{Int}()
116+
push!(t7, Int8(1))
117+
@test length(t7) == 1
118+
@test haskey(t7, 1)
71119
end
72120

73-
for i in visited
74-
@test search_key(t3, i)
75-
end
121+
@testset "minimum_node" begin
122+
t8 = RBTree()
123+
for i in 1:32
124+
push!(t8, i)
125+
end
126+
m1 = minimum_node(t8, t8.root)
127+
@test m1.data == 1
128+
node = t8.root
129+
while node.leftChild != t8.nil
130+
m = minimum_node(t8, node.leftChild)
131+
@test m == m1
132+
node = node.leftChild
133+
end
76134

135+
@test minimum_node(t8, t8.nil) === t8.nil
136+
end
77137
end

0 commit comments

Comments
 (0)