Skip to content

Commit 5c433f7

Browse files
authored
Merge pull request #645 from eulerkochy/splay_tree
SplayTree
2 parents 9658145 + 5ed3847 commit 5c433f7

File tree

8 files changed

+406
-3
lines changed

8 files changed

+406
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ This package implements a variety of data structures, including
3333
- DiBitVector (in which each element can store two bits)
3434
- Red Black Tree
3535
- AVL Tree
36+
- Splay Tree
3637

3738
Resources
3839
---------

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ makedocs(
2828
"dibit_vector.md",
2929
"red_black_tree.md",
3030
"avl_tree.md",
31+
"splay_tree.md",
3132
],
3233
modules = [DataStructures],
3334
format = Documenter.HTML()

docs/src/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ This package implements a variety of data structures, including
2525
- DiBitVector
2626
- Red Black Tree
2727
- AVL Tree
28+
- Splay Tree
2829

2930
## Contents
3031

@@ -51,6 +52,7 @@ Pages = [
5152
"sparse_int_set.md",
5253
"dibit_vector.md",
5354
"red_black_tree.md",
54-
"avl_tree.md"
55+
"avl_tree.md",
56+
"splay_tree.md",
5557
]
5658
```

docs/src/splay_tree.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
```@meta
2+
DocTestSetup = :(using DataStructures)
3+
```
4+
5+
# Splay Tree
6+
7+
The `SplayTree` type is an implementation of Splay Tree in Julia. It is a self-balancing binary search tree with the additional property that recently accessed elements are quick to access again. Operations such as search, insert and delete can be done in `O(log n)` amortized time, where `n` is the number of nodes in the `SplayTree`.
8+
9+
Examples:
10+
11+
```jldoctest
12+
julia> tree = SplayTree{Int}();
13+
14+
julia> for k in 1:2:20
15+
push!(tree, k)
16+
end
17+
18+
julia> haskey(tree, 3)
19+
true
20+
21+
julia> tree[4]
22+
7
23+
24+
julia> for k in 1:2:10
25+
delete!(tree, k)
26+
end
27+
28+
julia> haskey(tree, 5)
29+
false
30+
```
31+
32+
```@meta
33+
DocTestSetup = nothing
34+
```

src/DataStructures.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ module DataStructures
5151
export DiBitVector
5252

5353
export RBTree, search_node, minimum_node
54+
export SplayTree, maximum_node
5455
export AVLTree, sorted_rank
56+
export SplayTree, maximum_node
5557

5658
export findkey
5759

@@ -107,6 +109,7 @@ module DataStructures
107109
include("dibit_vector.jl")
108110
include("avl_tree.jl")
109111
include("red_black_tree.jl")
112+
include("splay_tree.jl")
110113

111114
include("deprecations.jl")
112115
end

src/splay_tree.jl

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
mutable struct SplayTreeNode{K}
2+
leftChild::Union{SplayTreeNode{K}, Nothing}
3+
rightChild::Union{SplayTreeNode{K}, Nothing}
4+
parent::Union{SplayTreeNode{K}, Nothing}
5+
data::K
6+
7+
SplayTreeNode{K}() where K = new{K}(nothing, nothing, nothing)
8+
SplayTreeNode{K}(d::K) where K = new{K}(nothing, nothing, nothing, d)
9+
end
10+
11+
SplayTreeNode(d) = SplayTreeNode{Any}(d)
12+
SplayTreeNode() = SplayTreeNode{Any}()
13+
14+
mutable struct SplayTree{K}
15+
root::Union{SplayTreeNode{K}, Nothing}
16+
count::Int
17+
18+
SplayTree{K}() where K = new{K}(nothing, 0)
19+
end
20+
21+
Base.length(tree::SplayTree) = tree.count
22+
23+
SplayTree() = SplayTree{Any}()
24+
25+
function left_rotate!(tree::SplayTree, node_x::SplayTreeNode)
26+
node_y = node_x.rightChild
27+
node_x.rightChild = node_y.leftChild
28+
if node_y.leftChild != nothing
29+
node_y.leftChild.parent = node_x
30+
end
31+
node_y.parent = node_x.parent
32+
33+
if node_x.parent == nothing
34+
tree.root = node_y
35+
elseif (node_x == node_x.parent.leftChild)
36+
node_x.parent.leftChild = node_y
37+
else
38+
node_x.parent.rightChild = node_y
39+
end
40+
if node_y != nothing
41+
node_y.leftChild = node_x
42+
end
43+
node_x.parent = node_y
44+
end
45+
46+
function right_rotate!(tree::SplayTree, node_x::SplayTreeNode)
47+
node_y = node_x.leftChild
48+
node_x.leftChild = node_y.rightChild
49+
if node_y.rightChild != nothing
50+
node_y.rightChild.parent = node_x
51+
end
52+
node_y.parent = node_x.parent
53+
if node_x.parent == nothing
54+
tree.root = node_y
55+
elseif (node_x == node_x.parent.leftChild)
56+
node_x.parent.leftChild = node_y
57+
else
58+
node_x.parent.rightChild = node_y
59+
end
60+
node_y.rightChild = node_x
61+
node_x.parent = node_y
62+
end
63+
64+
# The splaying operation moves node_x to the root of the tree using the series of rotations.
65+
function splay!(tree::SplayTree, node_x::SplayTreeNode)
66+
while node_x.parent !== nothing
67+
parent = node_x.parent
68+
grand_parent = node_x.parent.parent
69+
if grand_parent === nothing
70+
# single rotation
71+
if node_x == parent.leftChild
72+
# zig rotation
73+
right_rotate!(tree, node_x.parent)
74+
else
75+
# zag rotation
76+
left_rotate!(tree, node_x.parent)
77+
end
78+
# double rotation
79+
elseif node_x == parent.leftChild && parent == grand_parent.leftChild
80+
# zig-zig rotation
81+
right_rotate!(tree, grand_parent)
82+
right_rotate!(tree, parent)
83+
elseif node_x == parent.rightChild && parent == grand_parent.rightChild
84+
# zag-zag rotation
85+
left_rotate!(tree, grand_parent)
86+
left_rotate!(tree, parent)
87+
elseif node_x == parent.rightChild && parent == grand_parent.leftChild
88+
# zig-zag rotation
89+
left_rotate!(tree, node_x.parent)
90+
right_rotate!(tree, node_x.parent)
91+
else
92+
# zag-zig rotation
93+
right_rotate!(tree, node_x.parent)
94+
left_rotate!(tree, node_x.parent)
95+
end
96+
end
97+
end
98+
99+
function maximum_node(node::Union{SplayTreeNode, Nothing})
100+
(node == nothing) && return node
101+
while node.rightChild != nothing
102+
node = node.rightChild
103+
end
104+
return node
105+
end
106+
107+
# Join operations joins two trees S and T
108+
# All the items in S are smaller than the items in T.
109+
# This is a two-step process.
110+
# In the first step, splay the largest node in S. This moves the largest node to the root node.
111+
# In the second step, set the right child of the new root of S to T.
112+
function _join!(tree::SplayTree, s::Union{SplayTreeNode, Nothing}, t::Union{SplayTreeNode, Nothing})
113+
if s === nothing
114+
return t
115+
elseif t === nothing
116+
return s
117+
else
118+
x = maximum_node(s)
119+
splay!(tree, x)
120+
x.rightChild = t
121+
t.parent = x
122+
return x
123+
end
124+
end
125+
126+
function search_node(tree::SplayTree{K}, d::K) where K
127+
node = tree.root
128+
prev = nothing
129+
while node != nothing && node.data != d
130+
prev = node
131+
if node.data < d
132+
node = node.rightChild
133+
else
134+
node = node.leftChild
135+
end
136+
end
137+
return (node == nothing) ? prev : node
138+
end
139+
140+
function Base.haskey(tree::SplayTree{K}, d::K) where K
141+
node = tree.root
142+
if node === nothing
143+
return false
144+
else
145+
node = search_node(tree, d)
146+
(node === nothing) && return false
147+
is_found = (node.data == d)
148+
is_found && splay!(tree, node)
149+
return is_found
150+
end
151+
end
152+
153+
Base.in(key, tree::SplayTree) = haskey(tree, key)
154+
155+
function Base.delete!(tree::SplayTree{K}, d::K) where K
156+
node = tree.root
157+
x = search_node(tree, d)
158+
(x == nothing) && return tree
159+
t = nothing
160+
s = nothing
161+
162+
splay!(tree, x)
163+
164+
if x.rightChild !== nothing
165+
t = x.rightChild
166+
t.parent = nothing
167+
end
168+
169+
s = x
170+
s.rightChild = nothing
171+
172+
if s.leftChild !== nothing
173+
s.leftChild.parent = nothing
174+
end
175+
176+
tree.root = _join!(tree, s.leftChild, t)
177+
tree.count -= 1
178+
return tree
179+
end
180+
181+
function Base.push!(tree::SplayTree{K}, d0) where K
182+
d = convert(K, d0)
183+
is_present = search_node(tree, d)
184+
if (is_present !== nothing) && (is_present.data == d)
185+
return tree
186+
end
187+
# only unique keys are inserted
188+
node = SplayTreeNode{K}(d)
189+
y = nothing
190+
x = tree.root
191+
192+
while x !== nothing
193+
y = x
194+
if node.data > x.data
195+
x = x.rightChild
196+
else
197+
x = x.leftChild
198+
end
199+
end
200+
node.parent = y
201+
202+
if y === nothing
203+
tree.root = node
204+
elseif node.data < y.data
205+
y.leftChild = node
206+
else
207+
y.rightChild = node
208+
end
209+
splay!(tree, node)
210+
tree.count += 1
211+
return tree
212+
end
213+
214+
function Base.getindex(tree::SplayTree{K}, ind) where K
215+
@boundscheck (1 <= ind <= tree.count) || throw(KeyError("$ind should be in between 1 and $(tree.count)"))
216+
function traverse_tree_inorder(node::Union{SplayTreeNode, Nothing})
217+
if (node != nothing)
218+
left = traverse_tree_inorder(node.leftChild)
219+
right = traverse_tree_inorder(node.rightChild)
220+
append!(push!(left, node.data), right)
221+
else
222+
return K[]
223+
end
224+
end
225+
arr = traverse_tree_inorder(tree.root)
226+
return @inbounds arr[ind]
227+
end

test/runtests.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ tests = ["deprecations",
3232
"robin_dict",
3333
"ordered_robin_dict",
3434
"dibit_vector",
35-
"red_black_tree",
3635
"swiss_dict",
37-
"avl_tree"
36+
"avl_tree",
37+
"red_black_tree",
38+
"splay_tree"
3839
]
3940

4041
if length(ARGS) > 0

0 commit comments

Comments
 (0)