binary_search_tree 2.0 → 2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +32 -0
- data/README +76 -0
- data/Rakefile +1 -0
- data/binary_search_tree.gemspec +20 -0
- data/lib/binary_search_tree.rb +4 -522
- data/lib/binary_search_tree/binary_node.rb +42 -0
- data/lib/binary_search_tree/binary_search_tree.rb +493 -0
- data/lib/{binary_search_tree_hash.rb → binary_search_tree/binary_search_tree_hash.rb} +7 -7
- data/lib/binary_search_tree/version.rb +3 -0
- data/spec/binary_node_spec.rb +84 -0
- data/spec/binary_search_tree_spec.rb +107 -0
- metadata +31 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1146c21c38df640ed4d1660d3628ac131b045f73
|
4
|
+
data.tar.gz: 17f900353706322d84eb7d392223350914b65895
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5938628cedda9f0d9292c54fd5f45e93df32a2bcb226e5ec078c5dd53f79a76e9893423a2e26d9dbac9ea9ed6faff7dd4464f05e73974cf97f2270114b65ec7
|
7
|
+
data.tar.gz: 90bb4aff76e0097329279cd832a1af1f6b936a1a7be34e3f3ea72be5c13b58a900dcf3a7edbb0bd8cea542671ea774673f76fa450978d91bdd8e42000a043bae
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.swp
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
binary_search_tree (2.2)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.5)
|
10
|
+
rspec (3.4.0)
|
11
|
+
rspec-core (~> 3.4.0)
|
12
|
+
rspec-expectations (~> 3.4.0)
|
13
|
+
rspec-mocks (~> 3.4.0)
|
14
|
+
rspec-core (3.4.1)
|
15
|
+
rspec-support (~> 3.4.0)
|
16
|
+
rspec-expectations (3.4.0)
|
17
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
18
|
+
rspec-support (~> 3.4.0)
|
19
|
+
rspec-mocks (3.4.1)
|
20
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
+
rspec-support (~> 3.4.0)
|
22
|
+
rspec-support (3.4.1)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
binary_search_tree!
|
29
|
+
rspec
|
30
|
+
|
31
|
+
BUNDLED WITH
|
32
|
+
1.10.6
|
data/README
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
Installation:
|
2
|
+
gem install binary_search_tree
|
3
|
+
|
4
|
+
Info:
|
5
|
+
This gem implements the two classes BinarySearchTree and BinarySearchTreeHash. BinarySearchTree is a self balancing avl tree.
|
6
|
+
|
7
|
+
Most people will only need to be concerned with BinarySearchTreeHash as it is a wrapper over BinarySearchTree that provides the same interface as the native Ruby hash. This class is useful when you want a container that provides fast lookups with minimal memory footprint. Since it is self balancing, it will reorganize itself on every new insert to make subsequent lookups optimal.
|
8
|
+
|
9
|
+
-----------------------------------------
|
10
|
+
-----------------------------------------
|
11
|
+
--Example usage of BinarySearchTreeHash--
|
12
|
+
-----------------------------------------
|
13
|
+
-----------------------------------------
|
14
|
+
ruby-1.9.2> h = BinarySearchTreeHash.new logger (note: passing a logger is optional)
|
15
|
+
=> {}
|
16
|
+
ruby-1.9.2> (1..100).each{|i| h[i] = i*1000}
|
17
|
+
ruby-1.9.2> h[45]
|
18
|
+
DEBUG - [03/May/2011 15:02:07] "find operation completed in 7 lookups..."
|
19
|
+
=> 45000
|
20
|
+
ruby-1.9.2> h[77]
|
21
|
+
DEBUG - [03/May/2011 15:02:14] "find operation completed in 6 lookups..."
|
22
|
+
=> 77000
|
23
|
+
ruby-1.9.2> h[32]
|
24
|
+
DEBUG - [03/May/2011 15:02:18] "find operation completed in 2 lookups..."
|
25
|
+
=> 32000
|
26
|
+
ruby-1.9.2> h.delete 32
|
27
|
+
DEBUG - [03/May/2011 15:02:29] "find operation completed in 2 lookups..."
|
28
|
+
ruby-1.9.2> h[32]
|
29
|
+
DEBUG - [03/May/2011 15:02:58] "find operation completed in 8 lookups..."
|
30
|
+
=> nil
|
31
|
+
ruby-1.9.2> h[5000] = 7777
|
32
|
+
=> 7777
|
33
|
+
ruby-1.9.2> h[5000]
|
34
|
+
DEBUG - [03/May/2011 15:03:33] "find operation completed in 7 lookups..."
|
35
|
+
=> 7777
|
36
|
+
ruby-1.9.2> h.size
|
37
|
+
=> 100
|
38
|
+
ruby-1.9.2> h.delete 50
|
39
|
+
DEBUG - [03/May/2011 15:03:48] "find operation completed in 6 lookups..."
|
40
|
+
ruby-1.9.2> h.size
|
41
|
+
=> 99
|
42
|
+
|
43
|
+
---------------------------------------------------------------------------------------
|
44
|
+
---------------------------------------------------------------------------------------
|
45
|
+
--Example usage of BinarySearchTree (only use this if you want something lower level)--
|
46
|
+
---------------------------------------------------------------------------------------
|
47
|
+
---------------------------------------------------------------------------------------
|
48
|
+
ruby-1.9.2> b = BinarySearchTree.new logger (note: passing a logger is optional)
|
49
|
+
ruby-1.9.2> b.insert 45, 78
|
50
|
+
ruby-1.9.2> b.insert 23, 5
|
51
|
+
ruby-1.9.2> b.insert 77, 999
|
52
|
+
ruby-1.9.2> b.insert 43, 999
|
53
|
+
ruby-1.9.2> b.find(23).value
|
54
|
+
DEBUG - [03/May/2011 15:23:15] "find operation completed in 2 lookups..."
|
55
|
+
=> 5
|
56
|
+
ruby-1.9.2> b.find(24)
|
57
|
+
DEBUG - [03/May/2011 15:23:32] "find operation completed in 4 lookups..."
|
58
|
+
=> nil
|
59
|
+
ruby-1.9.2> b.find(43).value
|
60
|
+
DEBUG - [03/May/2011 15:23:40] "find operation completed in 3 lookups..."
|
61
|
+
=> 999
|
62
|
+
ruby-1.9.2> b.max.value
|
63
|
+
=> 999
|
64
|
+
ruby-1.9.2> b.min.value
|
65
|
+
=> 5
|
66
|
+
ruby-1.9.2> b.size
|
67
|
+
=> 4
|
68
|
+
ruby-1.9.2> b.remove 23
|
69
|
+
DEBUG - [03/May/2011 15:24:41] "find operation completed in 2 lookups..."
|
70
|
+
ruby-1.9.2> b.size
|
71
|
+
=> 3
|
72
|
+
ruby-1.9.2> b.clear
|
73
|
+
=> 0
|
74
|
+
ruby-1.9.2> b.size
|
75
|
+
=> 0
|
76
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'binary_search_tree/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "binary_search_tree"
|
8
|
+
s.version = BinarySearch::VERSION
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
s.authors = ["Misha Conway"]
|
13
|
+
s.email = "MishaAConway@gmail.com"
|
14
|
+
s.files = `git ls-files -z`.split("\x0")
|
15
|
+
s.licenses = ["MIT"]
|
16
|
+
s.rubyforge_project = "nowarning"
|
17
|
+
s.rubygems_version = "2.4.5"
|
18
|
+
s.summary = "A self balancing avl binary search tree class. Also includes BinarySearchTreeHash which is a hash like class that internally uses binary search tree."
|
19
|
+
s.add_development_dependency "rspec"
|
20
|
+
end
|
data/lib/binary_search_tree.rb
CHANGED
@@ -1,522 +1,4 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
def initialize key, value, parent
|
6
|
-
@key = key
|
7
|
-
@value = value
|
8
|
-
@parent = parent
|
9
|
-
@height = 0
|
10
|
-
end
|
11
|
-
|
12
|
-
def is_leaf?
|
13
|
-
height.zero?
|
14
|
-
end
|
15
|
-
|
16
|
-
def max_children_height
|
17
|
-
if left.present? && right.present?
|
18
|
-
[left.height, right.height].max
|
19
|
-
elsif left.present?
|
20
|
-
left.height
|
21
|
-
elsif right.present?
|
22
|
-
right.height
|
23
|
-
else
|
24
|
-
-1
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def balance_factor
|
29
|
-
(left.height rescue -1) - (right.height rescue -1)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
class BinarySearchTree
|
35
|
-
attr_reader :size, :root
|
36
|
-
|
37
|
-
def initialize logger=nil
|
38
|
-
@logger = logger
|
39
|
-
clear
|
40
|
-
end
|
41
|
-
|
42
|
-
def clear
|
43
|
-
@root = nil
|
44
|
-
@size = 0
|
45
|
-
end
|
46
|
-
|
47
|
-
def empty?
|
48
|
-
@root.nil?
|
49
|
-
end
|
50
|
-
|
51
|
-
def find key
|
52
|
-
@num_comparisons = 0
|
53
|
-
node = locate key, @root
|
54
|
-
@logger.debug "find operation completed in #{@num_comparisons} lookups..." if @logger.present?
|
55
|
-
node
|
56
|
-
end
|
57
|
-
|
58
|
-
def find_value value
|
59
|
-
find_value_ex @root, value
|
60
|
-
end
|
61
|
-
|
62
|
-
def min
|
63
|
-
@min ||= locate_min @root
|
64
|
-
end
|
65
|
-
|
66
|
-
def max
|
67
|
-
@max ||= locate_max @root
|
68
|
-
end
|
69
|
-
|
70
|
-
def insert element, value
|
71
|
-
put element, value, @root, nil
|
72
|
-
end
|
73
|
-
|
74
|
-
def remove node_or_key
|
75
|
-
delete node_or_key
|
76
|
-
end
|
77
|
-
|
78
|
-
def remove_min
|
79
|
-
delete min
|
80
|
-
end
|
81
|
-
|
82
|
-
def nodes
|
83
|
-
@nodes = []
|
84
|
-
serialize_nodes @root
|
85
|
-
@nodes
|
86
|
-
end
|
87
|
-
|
88
|
-
def == other_bst
|
89
|
-
compare @root, other_bst.root
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
def invalidate_cached_values
|
94
|
-
@min = @max = nil
|
95
|
-
end
|
96
|
-
|
97
|
-
def locate target, leaf
|
98
|
-
@num_comparisons += 1
|
99
|
-
if leaf.nil?
|
100
|
-
return nil
|
101
|
-
elsif leaf.key < target
|
102
|
-
return locate target, leaf.right
|
103
|
-
elsif leaf.key > target
|
104
|
-
return locate target, leaf.left
|
105
|
-
elsif leaf.key == target
|
106
|
-
return leaf
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def locate_min leaf
|
111
|
-
return nil if leaf.nil?
|
112
|
-
return leaf if leaf.left.nil?
|
113
|
-
return locate_min leaf.left
|
114
|
-
end
|
115
|
-
|
116
|
-
def locate_max leaf
|
117
|
-
return nil if leaf.nil?
|
118
|
-
return leaf if leaf.right.nil?
|
119
|
-
return locate_max leaf.right
|
120
|
-
end
|
121
|
-
|
122
|
-
def recompute_heights start_from_node
|
123
|
-
changed = true
|
124
|
-
node = start_from_node
|
125
|
-
while node && changed
|
126
|
-
old_height = node.height
|
127
|
-
if node.right.present? || node.left.present?
|
128
|
-
node.height = node.max_children_height + 1
|
129
|
-
else
|
130
|
-
node.height = 0
|
131
|
-
end
|
132
|
-
changed = node.height != old_height
|
133
|
-
node = node.parent
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def put element, value, leaf, parent, link_type=nil
|
138
|
-
#once you reach a point where you can place a new node
|
139
|
-
if leaf.nil?
|
140
|
-
#create that new node
|
141
|
-
leaf = BinaryNode.new element, value, parent
|
142
|
-
@size += 1
|
143
|
-
invalidate_cached_values
|
144
|
-
if parent.present?
|
145
|
-
if 'left' == link_type
|
146
|
-
parent.left = leaf
|
147
|
-
else
|
148
|
-
parent.right = leaf
|
149
|
-
end
|
150
|
-
else
|
151
|
-
@root = leaf
|
152
|
-
end
|
153
|
-
if parent.present? && parent.height.zero?
|
154
|
-
#if it has a parent but it is balanced, move up
|
155
|
-
node = parent
|
156
|
-
node_to_rebalance = nil
|
157
|
-
|
158
|
-
#continue moving up until you git the root
|
159
|
-
while node.present?
|
160
|
-
node.height = node.max_children_height + 1
|
161
|
-
if node.balance_factor.abs > 1
|
162
|
-
node_to_rebalance = node
|
163
|
-
break
|
164
|
-
end
|
165
|
-
node = node.parent
|
166
|
-
end
|
167
|
-
#if at any point you reach an unbalanced node, rebalance it
|
168
|
-
rebalance node_to_rebalance if node_to_rebalance.present?
|
169
|
-
end
|
170
|
-
|
171
|
-
elsif leaf.key < element
|
172
|
-
put element, value, leaf.right, leaf, "right"
|
173
|
-
elsif leaf.key > element
|
174
|
-
put element, value, leaf.left, leaf, "left"
|
175
|
-
elsif leaf.key == element
|
176
|
-
leaf.value = value
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
def find_value_ex leaf, value
|
181
|
-
if leaf.present?
|
182
|
-
node_with_value = find_value_ex leaf.left, value
|
183
|
-
return node_with_value if node_with_value.present?
|
184
|
-
return leaf if leaf.value == value
|
185
|
-
node_with_value = find_value_ex leaf.right, value
|
186
|
-
return node_with_value if node_with_value.present?
|
187
|
-
end
|
188
|
-
nil
|
189
|
-
end
|
190
|
-
|
191
|
-
def serialize_nodes leaf
|
192
|
-
if !leaf.nil?
|
193
|
-
serialize_nodes leaf.left
|
194
|
-
@nodes += [leaf]
|
195
|
-
serialize_nodes leaf.right
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def compare leaf, other_bst_leaf
|
200
|
-
if leaf.present? && other_bst_leaf.present?
|
201
|
-
leaf.value == other_bst_leaf.value &&
|
202
|
-
compare(leaf.left, other_bst_leaf.left) &&
|
203
|
-
compare(leaf.right, other_bst_leaf.right)
|
204
|
-
else
|
205
|
-
leaf.nil? && other_bst_leaf.nil?
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
def assert condition
|
210
|
-
raise "assertion failed" unless condition
|
211
|
-
end
|
212
|
-
|
213
|
-
def rrc_rebalance a, f
|
214
|
-
|
215
|
-
#puts "performing rrc rebalance"
|
216
|
-
b = a.right
|
217
|
-
c = b.right
|
218
|
-
assert a.present? && b.present? && c.present?
|
219
|
-
a.right = b.left
|
220
|
-
if a.right.present?
|
221
|
-
a.right.parent = a
|
222
|
-
end
|
223
|
-
b.left = a
|
224
|
-
a.parent = b
|
225
|
-
if f.nil?
|
226
|
-
@root = b
|
227
|
-
@root.parent = nil
|
228
|
-
else
|
229
|
-
if f.right == a
|
230
|
-
f.right = b
|
231
|
-
else
|
232
|
-
f.left = b
|
233
|
-
end
|
234
|
-
b.parent = f
|
235
|
-
end
|
236
|
-
recompute_heights a
|
237
|
-
recompute_heights b.parent
|
238
|
-
end
|
239
|
-
|
240
|
-
def rlc_rebalance a, f
|
241
|
-
|
242
|
-
#puts "performing rlc rebalance"
|
243
|
-
b = a.right
|
244
|
-
c = b.left
|
245
|
-
assert a.present? && b.present? && c.present?
|
246
|
-
b.left = c.right
|
247
|
-
if b.left.present?
|
248
|
-
b.left.parent = b
|
249
|
-
end
|
250
|
-
a.right = c.left
|
251
|
-
if a.right.present?
|
252
|
-
a.right.parent = a
|
253
|
-
end
|
254
|
-
c.right = b
|
255
|
-
b.parent = c
|
256
|
-
c.left = a
|
257
|
-
a.parent = c
|
258
|
-
if f.nil?
|
259
|
-
@root = c
|
260
|
-
@root.parent = nil
|
261
|
-
else
|
262
|
-
if f.right == a
|
263
|
-
f.right = c
|
264
|
-
else
|
265
|
-
f.left = c
|
266
|
-
end
|
267
|
-
c.parent = f
|
268
|
-
end
|
269
|
-
recompute_heights a
|
270
|
-
recompute_heights b
|
271
|
-
end
|
272
|
-
|
273
|
-
def llc_rebalance a, b, c, f
|
274
|
-
#puts "performing llc rebalance"
|
275
|
-
assert a.present? && b.present? && c.present?
|
276
|
-
a.left = b.right
|
277
|
-
if a.left
|
278
|
-
a.left.parent = a
|
279
|
-
end
|
280
|
-
b.right = a
|
281
|
-
a.parent = b
|
282
|
-
if f.nil?
|
283
|
-
@root = b
|
284
|
-
@root.parent = nil
|
285
|
-
else
|
286
|
-
if f.right == a
|
287
|
-
f.right = b
|
288
|
-
else
|
289
|
-
f.left = b
|
290
|
-
end
|
291
|
-
b.parent = f
|
292
|
-
end
|
293
|
-
recompute_heights a
|
294
|
-
recompute_heights b.parent
|
295
|
-
end
|
296
|
-
|
297
|
-
def lrc_rebalance a, b, c, f
|
298
|
-
#puts "performing lrc rebalance"
|
299
|
-
assert a.present? && b.present? && c.present?
|
300
|
-
a.left = c.right
|
301
|
-
if a.left.present?
|
302
|
-
a.left.parent = a
|
303
|
-
end
|
304
|
-
b.right = c.left
|
305
|
-
if b.right.present?
|
306
|
-
b.right.parent = b
|
307
|
-
end
|
308
|
-
c.left = b
|
309
|
-
b.parent = c
|
310
|
-
c.right = a
|
311
|
-
a.parent = c
|
312
|
-
if f.nil?
|
313
|
-
@root = c
|
314
|
-
@root.parent = nil
|
315
|
-
else
|
316
|
-
if f.right == a
|
317
|
-
f.right = c
|
318
|
-
else
|
319
|
-
f.left = c
|
320
|
-
end
|
321
|
-
c.parent = f
|
322
|
-
end
|
323
|
-
recompute_heights a
|
324
|
-
recompute_heights b
|
325
|
-
end
|
326
|
-
|
327
|
-
def rebalance node_to_rebalance
|
328
|
-
a = node_to_rebalance
|
329
|
-
f = a.parent #allowed to be NULL
|
330
|
-
if node_to_rebalance.balance_factor == -2
|
331
|
-
if node_to_rebalance.right.balance_factor <= 0
|
332
|
-
# """Rebalance, case RRC """
|
333
|
-
rrc_rebalance a, f
|
334
|
-
else
|
335
|
-
rlc_rebalance a, f
|
336
|
-
# """Rebalance, case RLC """
|
337
|
-
end
|
338
|
-
else
|
339
|
-
assert node_to_rebalance.balance_factor == 2
|
340
|
-
if node_to_rebalance.left.balance_factor >= 0
|
341
|
-
b = a.left
|
342
|
-
c = b.left
|
343
|
-
# """Rebalance, case LLC """
|
344
|
-
llc_rebalance a, b, c, f
|
345
|
-
else
|
346
|
-
b = a.left
|
347
|
-
c = b.right
|
348
|
-
# """Rebalance, case LRC """
|
349
|
-
lrc_rebalance a, b, c, f
|
350
|
-
end
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
def delete node_or_key
|
355
|
-
if BinaryNode == node_or_key.class
|
356
|
-
node = node_or_key
|
357
|
-
else
|
358
|
-
node = find node_or_key
|
359
|
-
end
|
360
|
-
|
361
|
-
if node.present?
|
362
|
-
@size -= 1
|
363
|
-
invalidate_cached_values
|
364
|
-
|
365
|
-
# There are three cases:
|
366
|
-
#
|
367
|
-
# 1) The node is a leaf. Remove it and return.
|
368
|
-
#
|
369
|
-
# 2) The node is a branch (has only 1 child). Make the pointer to this node
|
370
|
-
# point to the child of this node.
|
371
|
-
#
|
372
|
-
# 3) The node has two children. Swap items with the successor
|
373
|
-
# of the node (the smallest item in its right subtree) and
|
374
|
-
# delete the successor from the right subtree of the node.
|
375
|
-
if node.is_leaf?
|
376
|
-
remove_leaf node
|
377
|
-
elsif node.left.present? ^ node.right.present?
|
378
|
-
remove_branch node
|
379
|
-
else
|
380
|
-
assert node.left.present? && node.right.present?
|
381
|
-
swap_with_successor_and_remove node
|
382
|
-
end
|
383
|
-
end
|
384
|
-
node
|
385
|
-
end
|
386
|
-
|
387
|
-
def remove_leaf node
|
388
|
-
parent = node.parent
|
389
|
-
if parent.present?
|
390
|
-
if parent.left == node
|
391
|
-
parent.left = nil
|
392
|
-
else
|
393
|
-
assert parent.right == node
|
394
|
-
parent.right = nil
|
395
|
-
end
|
396
|
-
recompute_heights parent
|
397
|
-
else
|
398
|
-
@root = nil
|
399
|
-
end
|
400
|
-
#del node
|
401
|
-
# rebalance
|
402
|
-
node = parent
|
403
|
-
while node.present?
|
404
|
-
rebalance node if node.balance_factor.abs > 1
|
405
|
-
node = node.parent
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
|
410
|
-
def remove_branch node
|
411
|
-
parent = node.parent
|
412
|
-
if parent
|
413
|
-
if parent.left == node
|
414
|
-
if node.right.present?
|
415
|
-
parent.left = node.right
|
416
|
-
else
|
417
|
-
parent.left = node.left
|
418
|
-
end
|
419
|
-
else
|
420
|
-
assert parent.right == node
|
421
|
-
if node.right.present?
|
422
|
-
parent.right = node.right
|
423
|
-
else
|
424
|
-
parent.right = node.left
|
425
|
-
end
|
426
|
-
end
|
427
|
-
if node.left
|
428
|
-
node.left.parent = parent
|
429
|
-
else
|
430
|
-
assert node.right.present?
|
431
|
-
node.right.parent = parent
|
432
|
-
end
|
433
|
-
recompute_heights parent
|
434
|
-
|
435
|
-
end
|
436
|
-
|
437
|
-
#del node
|
438
|
-
# rebalance
|
439
|
-
node = parent
|
440
|
-
while node.present?
|
441
|
-
rebalance node if node.balance_factor.abs > 1
|
442
|
-
node = node.parent
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
def swap_with_successor_and_remove node
|
447
|
-
successor = locate_min node.right
|
448
|
-
swap_nodes node, successor
|
449
|
-
assert node.left.nil?
|
450
|
-
if node.height == 0
|
451
|
-
remove_leaf node
|
452
|
-
else
|
453
|
-
remove_branch node
|
454
|
-
end
|
455
|
-
end
|
456
|
-
|
457
|
-
def swap_nodes node1, node2
|
458
|
-
assert node1.height > node2.height
|
459
|
-
parent1 = node1.parent
|
460
|
-
left_child1 = node1.left
|
461
|
-
right_child1 = node1.right
|
462
|
-
parent2 = node2.parent
|
463
|
-
assert parent2.present?
|
464
|
-
assert parent2.left == node2 || parent2 == node1
|
465
|
-
left_child2 = node2.left
|
466
|
-
assert left_child2.nil?
|
467
|
-
right_child2 = node2.right
|
468
|
-
|
469
|
-
# swap heights
|
470
|
-
tmp = node1.height
|
471
|
-
node1.height = node2.height
|
472
|
-
node2.height = tmp
|
473
|
-
|
474
|
-
if parent1
|
475
|
-
if parent1.left == node1
|
476
|
-
parent1.left = node2
|
477
|
-
else
|
478
|
-
assert parent1.right == node1
|
479
|
-
parent1.right = node2
|
480
|
-
end
|
481
|
-
node2.parent = parent1
|
482
|
-
else
|
483
|
-
@root = node2
|
484
|
-
@root.parent = nil
|
485
|
-
end
|
486
|
-
|
487
|
-
node2.left = left_child1
|
488
|
-
left_child1.parent = node2
|
489
|
-
node1.left = left_child2 # None
|
490
|
-
node1.right = right_child2
|
491
|
-
if right_child2
|
492
|
-
right_child2.parent = node1
|
493
|
-
end
|
494
|
-
if parent2 != node1
|
495
|
-
node2.right = right_child1
|
496
|
-
right_child1.parent = node2
|
497
|
-
|
498
|
-
parent2.left = node1
|
499
|
-
node1.parent = parent2
|
500
|
-
else
|
501
|
-
node2.right = node1
|
502
|
-
node1.parent = node2
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
|
507
|
-
end
|
508
|
-
|
509
|
-
# #require 'binary_search_tree_hash.rb'
|
510
|
-
# tree = BinarySearchTree.new
|
511
|
-
# puts "inserting 9"
|
512
|
-
# tree.insert(9, "nine")
|
513
|
-
# puts "inserting 5"
|
514
|
-
# tree.insert(5, "five")
|
515
|
-
# puts "inserting 10"
|
516
|
-
# tree.insert(10, "ten")
|
517
|
-
# puts "inserting 1"
|
518
|
-
# tree.insert(1, "ten")
|
519
|
-
# puts "inserting 3"
|
520
|
-
# tree.insert(3, "ten")
|
521
|
-
# puts "inserting 7"
|
522
|
-
# tree.insert(7, "ten")
|
1
|
+
require "binary_search_tree/version"
|
2
|
+
require 'binary_search_tree/binary_node'
|
3
|
+
require 'binary_search_tree/binary_search_tree'
|
4
|
+
require 'binary_search_tree/binary_search_tree_hash'
|