binary_search_tree 1.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.
- data/lib/binary_search_tree.rb +480 -0
- data/lib/binary_search_tree_hash.rb +188 -0
- metadata +57 -0
@@ -0,0 +1,480 @@
|
|
1
|
+
class BinaryNode
|
2
|
+
attr_accessor :height, :parent, :left, :right, :key, :value
|
3
|
+
|
4
|
+
def initialize key, value, parent
|
5
|
+
@key = key
|
6
|
+
@value = value
|
7
|
+
@parent = parent
|
8
|
+
@height = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_leaf?
|
12
|
+
height.zero?
|
13
|
+
end
|
14
|
+
|
15
|
+
def max_children_height
|
16
|
+
if left.present? && right.present?
|
17
|
+
[left.height, right.height].max
|
18
|
+
elsif left.present?
|
19
|
+
left.height
|
20
|
+
elsif right.present?
|
21
|
+
right.height
|
22
|
+
else
|
23
|
+
-1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def balance_factor
|
28
|
+
(left.height rescue -1) - (right.height rescue -1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
class BinarySearchTree
|
34
|
+
attr_reader :size, :root
|
35
|
+
|
36
|
+
def initialize logger=nil
|
37
|
+
@logger = logger
|
38
|
+
clear
|
39
|
+
end
|
40
|
+
|
41
|
+
def clear
|
42
|
+
@root = nil
|
43
|
+
@size = 0
|
44
|
+
end
|
45
|
+
|
46
|
+
def empty?
|
47
|
+
@root.nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def find key
|
51
|
+
@num_comparisons = 0
|
52
|
+
node = locate key, @root
|
53
|
+
@logger.debug "find operation completed in #{@num_comparisons} lookups..." if @logger.present?
|
54
|
+
node
|
55
|
+
end
|
56
|
+
|
57
|
+
def find_value value
|
58
|
+
find_value_ex @root, value
|
59
|
+
end
|
60
|
+
|
61
|
+
def min
|
62
|
+
@min ||= locate_min @root
|
63
|
+
end
|
64
|
+
|
65
|
+
def max
|
66
|
+
@max ||= locate_max @root
|
67
|
+
end
|
68
|
+
|
69
|
+
def insert element, value
|
70
|
+
put element, value, @root, nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def remove node_or_key
|
74
|
+
delete node_or_key
|
75
|
+
end
|
76
|
+
|
77
|
+
def remove_min
|
78
|
+
delete min
|
79
|
+
end
|
80
|
+
|
81
|
+
def nodes
|
82
|
+
@nodes = []
|
83
|
+
serialize_nodes @root
|
84
|
+
@nodes
|
85
|
+
end
|
86
|
+
|
87
|
+
def == other_bst
|
88
|
+
compare @root, other_bst.root
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
def invalidate_cached_values
|
93
|
+
@min = @max = nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def locate target, leaf
|
97
|
+
@num_comparisons += 1
|
98
|
+
if leaf.nil?
|
99
|
+
return nil
|
100
|
+
elsif leaf.key < target
|
101
|
+
return locate target, leaf.right
|
102
|
+
elsif leaf.key > target
|
103
|
+
return locate target, leaf.left
|
104
|
+
elsif leaf.key == target
|
105
|
+
return leaf
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def locate_min leaf
|
110
|
+
return nil if leaf.nil?
|
111
|
+
return leaf if leaf.left.nil?
|
112
|
+
return locate_min leaf.left
|
113
|
+
end
|
114
|
+
|
115
|
+
def locate_max leaf
|
116
|
+
return nil if leaf.nil?
|
117
|
+
return leaf if leaf.right.nil?
|
118
|
+
return locate_max leaf.right
|
119
|
+
end
|
120
|
+
|
121
|
+
def recompute_heights start_from_node
|
122
|
+
changed = true
|
123
|
+
node = start_from_node
|
124
|
+
while node && changed
|
125
|
+
old_height = node.height
|
126
|
+
if node.right.present? || node.left.present?
|
127
|
+
node.height = node.max_children_height + 1
|
128
|
+
else
|
129
|
+
node.height = 0
|
130
|
+
end
|
131
|
+
changed = node.height != old_height
|
132
|
+
node = node.parent
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def put element, value, leaf, parent, link_type=nil
|
137
|
+
if leaf.nil?
|
138
|
+
leaf = BinaryNode.new element, value, parent
|
139
|
+
@size += 1
|
140
|
+
invalidate_cached_values
|
141
|
+
if parent.present?
|
142
|
+
if 'left' == link_type
|
143
|
+
parent.left = leaf
|
144
|
+
else
|
145
|
+
parent.right = leaf
|
146
|
+
end
|
147
|
+
else
|
148
|
+
@root = leaf
|
149
|
+
end
|
150
|
+
if parent.present? && parent.height.zero?
|
151
|
+
node = parent
|
152
|
+
node_to_rebalance = nil
|
153
|
+
while node.present?
|
154
|
+
node.height = node.max_children_height + 1
|
155
|
+
if node.balance_factor.abs > 1
|
156
|
+
node_to_rebalance = node
|
157
|
+
break
|
158
|
+
end
|
159
|
+
node = node.parent
|
160
|
+
end
|
161
|
+
rebalance node_to_rebalance if node_to_rebalance.present?
|
162
|
+
end
|
163
|
+
|
164
|
+
elsif leaf.key < element
|
165
|
+
put element, value, leaf.right, leaf, "right"
|
166
|
+
elsif leaf.key > element
|
167
|
+
put element, value, leaf.left, leaf, "left"
|
168
|
+
elsif leaf.key == element
|
169
|
+
leaf.value = value
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def find_value_ex leaf, value
|
174
|
+
if leaf.present?
|
175
|
+
node_with_value = find_value_ex leaf.left, value
|
176
|
+
return node_with_value if node_with_value.present?
|
177
|
+
return leaf if leaf.value == value
|
178
|
+
node_with_value = find_value_ex leaf.right, value
|
179
|
+
return node_with_value if node_with_value.present?
|
180
|
+
end
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
def serialize_nodes leaf
|
185
|
+
if !leaf.nil?
|
186
|
+
serialize_nodes leaf.left
|
187
|
+
@nodes += [leaf]
|
188
|
+
serialize_nodes leaf.right
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def compare leaf, other_bst_leaf
|
193
|
+
if leaf.present? && other_bst_leaf.present?
|
194
|
+
leaf.value == other_bst_leaf.value &&
|
195
|
+
compare(leaf.left, other_bst_leaf.left) &&
|
196
|
+
compare(leaf.right, other_bst_leaf.right)
|
197
|
+
else
|
198
|
+
leaf.nil? && other_bst_leaf.nil?
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def assert condition
|
203
|
+
raise "assertion failed" unless condition
|
204
|
+
end
|
205
|
+
|
206
|
+
def rebalance node_to_rebalance
|
207
|
+
a = node_to_rebalance
|
208
|
+
f = a.parent #allowed to be NULL
|
209
|
+
if node_to_rebalance.balance_factor == -2
|
210
|
+
if node_to_rebalance.right.balance_factor <= 0
|
211
|
+
# """Rebalance, case RRC """
|
212
|
+
b = a.right
|
213
|
+
c = b.right
|
214
|
+
assert a.present? && b.present? && c.present?
|
215
|
+
a.right = b.left
|
216
|
+
if a.right.present?
|
217
|
+
a.right.parent = a
|
218
|
+
end
|
219
|
+
b.left = a
|
220
|
+
a.parent = b
|
221
|
+
if f.nil?
|
222
|
+
@root = b
|
223
|
+
@root.parent = nil
|
224
|
+
else
|
225
|
+
if f.right == a
|
226
|
+
f.right = b
|
227
|
+
else
|
228
|
+
f.left = b
|
229
|
+
end
|
230
|
+
b.parent = f
|
231
|
+
end
|
232
|
+
recompute_heights a
|
233
|
+
recompute_heights b.parent
|
234
|
+
else
|
235
|
+
# """Rebalance, case RLC """
|
236
|
+
b = a.right
|
237
|
+
c = b.left
|
238
|
+
assert a.present? && b.present? && c.present?
|
239
|
+
b.left = c.right
|
240
|
+
if b.left.present?
|
241
|
+
b.left.parent = b
|
242
|
+
end
|
243
|
+
a.right = c.left
|
244
|
+
if a.right.present?
|
245
|
+
a.right.parent = a
|
246
|
+
end
|
247
|
+
c.right = b
|
248
|
+
b.parent = c
|
249
|
+
c.left = a
|
250
|
+
a.parent = c
|
251
|
+
if f.nil?
|
252
|
+
@root = c
|
253
|
+
@root.parent = nil
|
254
|
+
else
|
255
|
+
if f.right == a
|
256
|
+
f.right = c
|
257
|
+
else
|
258
|
+
f.left = c
|
259
|
+
end
|
260
|
+
c.parent = f
|
261
|
+
end
|
262
|
+
recompute_heights a
|
263
|
+
recompute_heights b
|
264
|
+
end
|
265
|
+
else
|
266
|
+
assert node_to_rebalance.balance_factor == 2
|
267
|
+
if node_to_rebalance.left.balance_factor >= 0
|
268
|
+
b = a.left
|
269
|
+
c = b.left
|
270
|
+
# """Rebalance, case LLC """
|
271
|
+
assert a.present? && b.present? && c.present?
|
272
|
+
a.left = b.right
|
273
|
+
if a.left
|
274
|
+
a.left.parent = a
|
275
|
+
end
|
276
|
+
b.right = a
|
277
|
+
a.parent = b
|
278
|
+
if f.nil?
|
279
|
+
@root = b
|
280
|
+
@root.parent = nil
|
281
|
+
else
|
282
|
+
if f.right == a
|
283
|
+
f.right = b
|
284
|
+
else
|
285
|
+
f.left = b
|
286
|
+
end
|
287
|
+
b.parent = f
|
288
|
+
end
|
289
|
+
recompute_heights a
|
290
|
+
recompute_heights b.parent
|
291
|
+
else
|
292
|
+
b = a.left
|
293
|
+
c = b.right
|
294
|
+
# """Rebalance, case LRC """
|
295
|
+
assert a.present? && b.present? && c.present?
|
296
|
+
a.left = c.right
|
297
|
+
if a.left.present?
|
298
|
+
a.left.parent = a
|
299
|
+
end
|
300
|
+
b.right = c.left
|
301
|
+
if b.right.present?
|
302
|
+
b.right.parent = b
|
303
|
+
end
|
304
|
+
c.left = b
|
305
|
+
b.parent = c
|
306
|
+
c.right = a
|
307
|
+
a.parent = c
|
308
|
+
if f.nil?
|
309
|
+
@root = c
|
310
|
+
@root.parent = nil
|
311
|
+
else
|
312
|
+
if f.right == a
|
313
|
+
f.right = c
|
314
|
+
else
|
315
|
+
f.left = c
|
316
|
+
end
|
317
|
+
c.parent = f
|
318
|
+
end
|
319
|
+
recompute_heights a
|
320
|
+
recompute_heights b
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def delete node_or_key
|
326
|
+
if BinaryNode == node_or_key.class
|
327
|
+
node = node_or_key
|
328
|
+
else
|
329
|
+
node = find node_or_key
|
330
|
+
end
|
331
|
+
|
332
|
+
if node.present?
|
333
|
+
@size -= 1
|
334
|
+
invalidate_cached_values
|
335
|
+
|
336
|
+
# There are three cases:
|
337
|
+
#
|
338
|
+
# 1) The node is a leaf. Remove it and return.
|
339
|
+
#
|
340
|
+
# 2) The node is a branch (has only 1 child). Make the pointer to this node
|
341
|
+
# point to the child of this node.
|
342
|
+
#
|
343
|
+
# 3) The node has two children. Swap items with the successor
|
344
|
+
# of the node (the smallest item in its right subtree) and
|
345
|
+
# delete the successor from the right subtree of the node.
|
346
|
+
if node.is_leaf?
|
347
|
+
remove_leaf node
|
348
|
+
elsif node.left.present? ^ node.right.present?
|
349
|
+
remove_branch node
|
350
|
+
else
|
351
|
+
assert node.left.present? && node.right.present?
|
352
|
+
swap_with_successor_and_remove node
|
353
|
+
end
|
354
|
+
end
|
355
|
+
node
|
356
|
+
end
|
357
|
+
|
358
|
+
def remove_leaf node
|
359
|
+
parent = node.parent
|
360
|
+
if parent.present?
|
361
|
+
if parent.left == node
|
362
|
+
parent.left = nil
|
363
|
+
else
|
364
|
+
assert parent.right == node
|
365
|
+
parent.right = nil
|
366
|
+
end
|
367
|
+
recompute_heights parent
|
368
|
+
else
|
369
|
+
@root = nil
|
370
|
+
end
|
371
|
+
#del node
|
372
|
+
# rebalance
|
373
|
+
node = parent
|
374
|
+
while node.present?
|
375
|
+
rebalance node if node.balance_factor.abs > 1
|
376
|
+
node = node.parent
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
|
381
|
+
def remove_branch node
|
382
|
+
parent = node.parent
|
383
|
+
if parent
|
384
|
+
if parent.left == node
|
385
|
+
if node.right.present?
|
386
|
+
parent.left = node.right
|
387
|
+
else
|
388
|
+
parent.left = node.left
|
389
|
+
end
|
390
|
+
else
|
391
|
+
assert parent.right == node
|
392
|
+
if node.right.present?
|
393
|
+
parent.right = node.right
|
394
|
+
else
|
395
|
+
parent.right = node.left
|
396
|
+
end
|
397
|
+
end
|
398
|
+
if node.left
|
399
|
+
node.left.parent = parent
|
400
|
+
else
|
401
|
+
assert node.right.present?
|
402
|
+
node.right.parent = parent
|
403
|
+
end
|
404
|
+
recompute_heights parent
|
405
|
+
|
406
|
+
end
|
407
|
+
|
408
|
+
#del node
|
409
|
+
# rebalance
|
410
|
+
node = parent
|
411
|
+
while node.present?
|
412
|
+
rebalance node if node.balance_factor.abs > 1
|
413
|
+
node = node.parent
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def swap_with_successor_and_remove node
|
418
|
+
successor = locate_min node.right
|
419
|
+
swap_nodes node, successor
|
420
|
+
assert node.left.nil?
|
421
|
+
if node.height == 0
|
422
|
+
remove_leaf node
|
423
|
+
else
|
424
|
+
remove_branch node
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def swap_nodes node1, node2
|
429
|
+
assert node1.height > node2.height
|
430
|
+
parent1 = node1.parent
|
431
|
+
left_child1 = node1.left
|
432
|
+
right_child1 = node1.right
|
433
|
+
parent2 = node2.parent
|
434
|
+
assert parent2.present?
|
435
|
+
assert parent2.left == node2 || parent2 == node1
|
436
|
+
left_child2 = node2.left
|
437
|
+
assert left_child2.nil?
|
438
|
+
right_child2 = node2.right
|
439
|
+
|
440
|
+
# swap heights
|
441
|
+
tmp = node1.height
|
442
|
+
node1.height = node2.height
|
443
|
+
node2.height = tmp
|
444
|
+
|
445
|
+
if parent1
|
446
|
+
if parent1.left == node1
|
447
|
+
parent1.left = node2
|
448
|
+
else
|
449
|
+
assert parent1.right == node1
|
450
|
+
parent1.right = node2
|
451
|
+
end
|
452
|
+
node2.parent = parent1
|
453
|
+
else
|
454
|
+
@root = node2
|
455
|
+
@root.parent = nil
|
456
|
+
end
|
457
|
+
|
458
|
+
node2.left = left_child1
|
459
|
+
left_child1.parent = node2
|
460
|
+
node1.left = left_child2 # None
|
461
|
+
node1.right = right_child2
|
462
|
+
if right_child2
|
463
|
+
right_child2.parent = node1
|
464
|
+
end
|
465
|
+
if parent2 != node1
|
466
|
+
node2.right = right_child1
|
467
|
+
right_child1.parent = node2
|
468
|
+
|
469
|
+
parent2.left = node1
|
470
|
+
node1.parent = parent2
|
471
|
+
else
|
472
|
+
node2.right = node1
|
473
|
+
node1.parent = node2
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
|
478
|
+
end
|
479
|
+
|
480
|
+
require 'binary_search_tree_hash.rb'
|
@@ -0,0 +1,188 @@
|
|
1
|
+
class BinarySearchTreeHash
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
def initialize logger=nil
|
5
|
+
@bst = BinarySearchTree.new logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def clear
|
9
|
+
@bst.clear
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def empty?
|
14
|
+
@bst.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def [] key
|
18
|
+
node = @bst.find key
|
19
|
+
node.present?? node.value : nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def []=(key, value)
|
23
|
+
@bst.insert key, value
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete key
|
27
|
+
@bst.remove key
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_hash
|
32
|
+
h = {}
|
33
|
+
each{ |key, value| h[key] = value }
|
34
|
+
h
|
35
|
+
end
|
36
|
+
alias :to_h :to_hash
|
37
|
+
|
38
|
+
def keys
|
39
|
+
map{ |node| node.first }
|
40
|
+
end
|
41
|
+
|
42
|
+
def values
|
43
|
+
map{ |node| node.second }
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_a
|
47
|
+
map{ |node| [node.first, node.second] }
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
'{' + map{ |node| "#{node.first} => #{node.second}" }.join(', ') + '}'
|
52
|
+
end
|
53
|
+
|
54
|
+
def min
|
55
|
+
[@bst.min.key, @bst.min.value]
|
56
|
+
end
|
57
|
+
|
58
|
+
def max
|
59
|
+
[@bst.max.key, @bst.max.value]
|
60
|
+
end
|
61
|
+
|
62
|
+
def each
|
63
|
+
@bst.nodes.each { |node| yield [node.key, node.value] }
|
64
|
+
end
|
65
|
+
|
66
|
+
def each_key
|
67
|
+
@bst.nodes.each{ |node| yield node.key }
|
68
|
+
end
|
69
|
+
|
70
|
+
def each_value
|
71
|
+
@bst.nodes.each{ |node| yield node.value }
|
72
|
+
end
|
73
|
+
|
74
|
+
def each_pair
|
75
|
+
@bst.nodes.each{ |node| yield node.key, node.value }
|
76
|
+
end
|
77
|
+
|
78
|
+
def select
|
79
|
+
@bst.nodes.select{ |node| yield node.key, node.value }.map{ |node| [node.key, node.value] }
|
80
|
+
end
|
81
|
+
|
82
|
+
def reject
|
83
|
+
@bst.nodes.reject{ |node| yield node.key, node.value }.map{ |node| [node.key, node.value] }
|
84
|
+
end
|
85
|
+
|
86
|
+
def reject!
|
87
|
+
changed = false
|
88
|
+
nodes = @bst.nodes
|
89
|
+
nodes.each_with_index do |node, i|
|
90
|
+
if yield node.key, node.value
|
91
|
+
changed = true
|
92
|
+
@bst.remove node
|
93
|
+
nodes[i] = nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
changed ? nodes.compact.map{ |node| [node.key, node.value] } : nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def delete_if
|
100
|
+
nodes = @bst.nodes
|
101
|
+
nodes.each_with_index do |node, i|
|
102
|
+
if yield node.key, node.value
|
103
|
+
@bst.remove node
|
104
|
+
nodes[i] = nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
nodes.compact.map{ |node| [node.key, node.value] }
|
108
|
+
end
|
109
|
+
|
110
|
+
def size
|
111
|
+
@bst.size
|
112
|
+
end
|
113
|
+
alias :length :size
|
114
|
+
|
115
|
+
def has_key? key
|
116
|
+
@bst.find(key).present?
|
117
|
+
end
|
118
|
+
|
119
|
+
def include? key
|
120
|
+
has_key? key
|
121
|
+
end
|
122
|
+
|
123
|
+
def key? key
|
124
|
+
has_key? key
|
125
|
+
end
|
126
|
+
|
127
|
+
def member? key
|
128
|
+
has_key? key
|
129
|
+
end
|
130
|
+
|
131
|
+
def has_value? value
|
132
|
+
@bst.find_value(value).present?
|
133
|
+
end
|
134
|
+
|
135
|
+
def value? value
|
136
|
+
has_value? value
|
137
|
+
end
|
138
|
+
|
139
|
+
def key value
|
140
|
+
@bst.find_value(value).key
|
141
|
+
end
|
142
|
+
|
143
|
+
def values_at key, *extra_keys
|
144
|
+
#TODO: optimize this so that only one tree traversal occurs
|
145
|
+
([key] + extra_keys).map{ |key| @bst.find(key).value }
|
146
|
+
end
|
147
|
+
|
148
|
+
def shift
|
149
|
+
deleted_node = @bst.remove_min
|
150
|
+
deleted_node.present?? [deleted_node.key, deleted_node.value] : nil
|
151
|
+
end
|
152
|
+
|
153
|
+
def invert
|
154
|
+
inverted_bst_hash = BinarySearchTreeHash.new
|
155
|
+
each{ |key, value| inverted_bst_hash[value] = key }
|
156
|
+
inverted_bst_hash
|
157
|
+
end
|
158
|
+
|
159
|
+
def replace other_bst_hash
|
160
|
+
clear
|
161
|
+
merge! other_bst_hash
|
162
|
+
end
|
163
|
+
|
164
|
+
def merge other_bst_hash
|
165
|
+
merged_hash = BinarySearchTreeHash.new
|
166
|
+
each{ |key, value| merged_hash[key] = value}
|
167
|
+
other_bst_hash.each{ |key, value| merged_hash[key] = value }
|
168
|
+
merged_hash
|
169
|
+
end
|
170
|
+
|
171
|
+
def merge! other_bst_hash
|
172
|
+
other_bst_hash.each{ |key, value| self[key] = value }
|
173
|
+
self
|
174
|
+
end
|
175
|
+
|
176
|
+
def update other_bst_hash
|
177
|
+
merge! other_bst_hash
|
178
|
+
end
|
179
|
+
|
180
|
+
def == other_bst_hash
|
181
|
+
bst == other_bst_hash.send(:bst)
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
def bst
|
186
|
+
@bst
|
187
|
+
end
|
188
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: binary_search_tree
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: "1.2"
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Misha Conway
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-03 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description:
|
18
|
+
email: MishaAConway@gmail.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- lib/binary_search_tree.rb
|
27
|
+
- lib/binary_search_tree_hash.rb
|
28
|
+
has_rdoc: true
|
29
|
+
homepage:
|
30
|
+
licenses: []
|
31
|
+
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project: nowarning
|
52
|
+
rubygems_version: 1.6.1
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: A self balancing avl binary search tree class. Also includes BinarySearchTreeHash which is a hash like class that internally uses binary search tree.
|
56
|
+
test_files: []
|
57
|
+
|