avl_tree 1.1.1 → 1.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/bench/bench.rb +0 -2
- data/lib/avl_tree.rb +57 -59
- data/lib/red_black_tree.rb +30 -37
- data/test/test_avl_tree.rb +6 -0
- data/test/test_red_black_tree.rb +12 -6
- metadata +2 -2
data/bench/bench.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'benchmark'
|
2
|
-
require 'radix_tree' # gem install radix_tree
|
3
2
|
require 'avl_tree'
|
4
3
|
require 'red_black_tree'
|
5
4
|
require 'openssl'
|
@@ -47,7 +46,6 @@ end
|
|
47
46
|
|
48
47
|
Benchmark.bmbm do |bm|
|
49
48
|
run(bm, Hash.new, keys)
|
50
|
-
run(bm, RadixTree.new, keys)
|
51
49
|
run(bm, AVLTree.new, keys)
|
52
50
|
run(bm, RedBlackTree.new, keys)
|
53
51
|
end
|
data/lib/avl_tree.rb
CHANGED
@@ -4,65 +4,6 @@ class AVLTree
|
|
4
4
|
class Node
|
5
5
|
UNDEFINED = Object.new
|
6
6
|
|
7
|
-
class EmptyNode
|
8
|
-
def empty?
|
9
|
-
true
|
10
|
-
end
|
11
|
-
|
12
|
-
def height
|
13
|
-
0
|
14
|
-
end
|
15
|
-
|
16
|
-
def value
|
17
|
-
nil
|
18
|
-
end
|
19
|
-
|
20
|
-
def size
|
21
|
-
0
|
22
|
-
end
|
23
|
-
|
24
|
-
def each(&block)
|
25
|
-
# intentionally blank
|
26
|
-
end
|
27
|
-
|
28
|
-
# returns new_root
|
29
|
-
def insert(key, value)
|
30
|
-
Node.new(key, value)
|
31
|
-
end
|
32
|
-
|
33
|
-
# returns value
|
34
|
-
def retrieve(key)
|
35
|
-
UNDEFINED
|
36
|
-
end
|
37
|
-
|
38
|
-
# returns [deleted_node, new_root]
|
39
|
-
def delete(key)
|
40
|
-
[self, self]
|
41
|
-
end
|
42
|
-
|
43
|
-
def dump_tree(io, indent = '')
|
44
|
-
# intentionally blank
|
45
|
-
end
|
46
|
-
|
47
|
-
def dump_sexp
|
48
|
-
# intentionally blank
|
49
|
-
end
|
50
|
-
|
51
|
-
def rotate
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def update_height
|
56
|
-
# intentionally blank
|
57
|
-
end
|
58
|
-
|
59
|
-
# for debugging
|
60
|
-
def check_height
|
61
|
-
# intentionally blank
|
62
|
-
end
|
63
|
-
end
|
64
|
-
EMPTY = Node::EmptyNode.new
|
65
|
-
|
66
7
|
attr_reader :key, :value, :height
|
67
8
|
attr_reader :left, :right
|
68
9
|
|
@@ -285,6 +226,63 @@ class AVLTree
|
|
285
226
|
end
|
286
227
|
pool
|
287
228
|
end
|
229
|
+
|
230
|
+
class EmptyNode < Node
|
231
|
+
def initialize
|
232
|
+
@value = nil
|
233
|
+
@height = 0
|
234
|
+
end
|
235
|
+
|
236
|
+
def empty?
|
237
|
+
true
|
238
|
+
end
|
239
|
+
|
240
|
+
def size
|
241
|
+
0
|
242
|
+
end
|
243
|
+
|
244
|
+
def each(&block)
|
245
|
+
# intentionally blank
|
246
|
+
end
|
247
|
+
|
248
|
+
# returns new_root
|
249
|
+
def insert(key, value)
|
250
|
+
Node.new(key, value)
|
251
|
+
end
|
252
|
+
|
253
|
+
# returns value
|
254
|
+
def retrieve(key)
|
255
|
+
UNDEFINED
|
256
|
+
end
|
257
|
+
|
258
|
+
# returns [deleted_node, new_root]
|
259
|
+
def delete(key)
|
260
|
+
[self, self]
|
261
|
+
end
|
262
|
+
|
263
|
+
def dump_tree(io, indent = '')
|
264
|
+
# intentionally blank
|
265
|
+
end
|
266
|
+
|
267
|
+
def dump_sexp
|
268
|
+
# intentionally blank
|
269
|
+
end
|
270
|
+
|
271
|
+
def rotate
|
272
|
+
self
|
273
|
+
end
|
274
|
+
|
275
|
+
def update_height
|
276
|
+
# intentionally blank
|
277
|
+
end
|
278
|
+
|
279
|
+
# for debugging
|
280
|
+
def check_height
|
281
|
+
# intentionally blank
|
282
|
+
end
|
283
|
+
end
|
284
|
+
EMPTY = Node::EmptyNode.new.freeze
|
285
|
+
|
288
286
|
end
|
289
287
|
|
290
288
|
DEFAULT = Object.new
|
data/lib/red_black_tree.rb
CHANGED
@@ -67,18 +67,18 @@ class RedBlackTree
|
|
67
67
|
case key <=> @key
|
68
68
|
when -1
|
69
69
|
@left = @left.insert(key, value)
|
70
|
-
if black? and @left.red? and !@left.children_both_black?
|
70
|
+
if black? and @right.black? and @left.red? and !@left.children_both_black?
|
71
71
|
ret = rebalance_for_left_insert
|
72
72
|
end
|
73
73
|
when 0
|
74
74
|
@value = value
|
75
75
|
when 1
|
76
76
|
@right = @right.insert(key, value)
|
77
|
-
if black? and @right.red? and !@right.children_both_black?
|
77
|
+
if black? and @left.black? and @right.red? and !@right.children_both_black?
|
78
78
|
ret = rebalance_for_right_insert
|
79
79
|
end
|
80
80
|
end
|
81
|
-
ret
|
81
|
+
ret.pullup_red
|
82
82
|
end
|
83
83
|
|
84
84
|
# returns value
|
@@ -304,40 +304,40 @@ class RedBlackTree
|
|
304
304
|
root
|
305
305
|
end
|
306
306
|
|
307
|
+
# Pull up red nodes
|
308
|
+
# (b (A C)) where A and C are RED --> (B (a c))
|
309
|
+
#
|
310
|
+
# b B
|
311
|
+
# / \ -> / \
|
312
|
+
# A C a c
|
313
|
+
#
|
314
|
+
def pullup_red
|
315
|
+
if black? and @left.red? and @right.red?
|
316
|
+
@left.color = @right.color = :BLACK
|
317
|
+
self.color = :RED
|
318
|
+
end
|
319
|
+
self
|
320
|
+
end
|
321
|
+
|
307
322
|
private
|
308
323
|
|
309
324
|
# trying to rebalance when the left sub-tree is 1 level higher than the right
|
310
325
|
# precondition: self is black and @left is red
|
311
326
|
def rebalance_for_left_insert
|
312
|
-
|
313
|
-
if @right.red?
|
314
|
-
|
315
|
-
@color = :RED
|
316
|
-
@left.color = @right.color = :BLACK
|
317
|
-
else
|
318
|
-
# move 1 black from the left to the right by single/double rotation
|
319
|
-
if @left.right.red?
|
320
|
-
@left = @left.rotate_left
|
321
|
-
end
|
322
|
-
ret = rotate_right
|
327
|
+
# move 1 black from the left to the right by single/double rotation
|
328
|
+
if @left.right.red?
|
329
|
+
@left = @left.rotate_left
|
323
330
|
end
|
324
|
-
|
331
|
+
rotate_right
|
325
332
|
end
|
326
333
|
|
327
334
|
# trying to rebalance when the right sub-tree is 1 level higher than the left
|
328
335
|
# See rebalance_for_left_insert.
|
329
336
|
def rebalance_for_right_insert
|
330
|
-
|
331
|
-
|
332
|
-
@color = :RED
|
333
|
-
@left.color = @right.color = :BLACK
|
334
|
-
else
|
335
|
-
if @right.left.red?
|
336
|
-
@right = @right.rotate_right
|
337
|
-
end
|
338
|
-
ret = rotate_left
|
337
|
+
if @right.left.red?
|
338
|
+
@right = @right.rotate_right
|
339
339
|
end
|
340
|
-
|
340
|
+
rotate_left
|
341
341
|
end
|
342
342
|
|
343
343
|
def delete_self
|
@@ -377,23 +377,16 @@ class RedBlackTree
|
|
377
377
|
pool
|
378
378
|
end
|
379
379
|
|
380
|
-
class EmptyNode
|
381
|
-
def
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
def black?
|
386
|
-
true
|
380
|
+
class EmptyNode < Node
|
381
|
+
def initialize
|
382
|
+
@value = nil
|
383
|
+
@color = :BLACK
|
387
384
|
end
|
388
385
|
|
389
386
|
def empty?
|
390
387
|
true
|
391
388
|
end
|
392
389
|
|
393
|
-
def value
|
394
|
-
nil
|
395
|
-
end
|
396
|
-
|
397
390
|
def size
|
398
391
|
0
|
399
392
|
end
|
@@ -425,7 +418,7 @@ class RedBlackTree
|
|
425
418
|
# intentionally blank
|
426
419
|
end
|
427
420
|
end
|
428
|
-
EMPTY = Node::EmptyNode.new
|
421
|
+
EMPTY = Node::EmptyNode.new.freeze
|
429
422
|
end
|
430
423
|
|
431
424
|
DEFAULT = Object.new
|
data/test/test_avl_tree.rb
CHANGED
@@ -432,6 +432,12 @@ class TestAVLTree < Test::Unit::TestCase
|
|
432
432
|
assert_equal [1.3, 'a' ], h.first
|
433
433
|
end
|
434
434
|
|
435
|
+
def test_values_for_empty_tree
|
436
|
+
h = AVLTree.new
|
437
|
+
|
438
|
+
assert_equal [], h.values
|
439
|
+
end
|
440
|
+
|
435
441
|
if RUBY_VERSION >= '1.9.0'
|
436
442
|
# In contrast to RadixTree, AVLTree just uses String#<=> as-is
|
437
443
|
def test_encoding
|
data/test/test_red_black_tree.rb
CHANGED
@@ -51,7 +51,7 @@ class TestRedBlackTree < Test::Unit::TestCase
|
|
51
51
|
h['c'] = 6
|
52
52
|
assert_equal '(b a (g (d c) h))', h.dump_sexp
|
53
53
|
h['e'] = 6
|
54
|
-
assert_equal '(b a (g
|
54
|
+
assert_equal '(d (b a c) (g e h))', h.dump_sexp
|
55
55
|
h['f'] = 6
|
56
56
|
assert_equal '(d (b a c) (g (e - f) h))', h.dump_sexp
|
57
57
|
end
|
@@ -67,7 +67,7 @@ class TestRedBlackTree < Test::Unit::TestCase
|
|
67
67
|
h['0'] = 7
|
68
68
|
h['c'] = 8
|
69
69
|
h['e'] = 9
|
70
|
-
assert_equal '(
|
70
|
+
assert_equal '(d (b (a 0) c) (g e (h - i)))', h.dump_sexp
|
71
71
|
h['f'] = 10
|
72
72
|
assert_equal '(d (b (a 0) c) (g (e - f) (h - i)))', h.dump_sexp
|
73
73
|
end
|
@@ -247,9 +247,9 @@ class TestRedBlackTree < Test::Unit::TestCase
|
|
247
247
|
h['f'] = 8
|
248
248
|
h['h'] = 9
|
249
249
|
h['j'] = 10
|
250
|
-
assert_equal '(c (b a) (g
|
250
|
+
assert_equal '(e (c (b a) d) (g f (i h j)))', h.dump_sexp
|
251
251
|
h.delete('g')
|
252
|
-
assert_equal '(c (b a) (h
|
252
|
+
assert_equal '(e (c (b a) d) (h f (i - j)))', h.dump_sexp
|
253
253
|
end
|
254
254
|
|
255
255
|
def test_delete_node_left
|
@@ -264,9 +264,9 @@ class TestRedBlackTree < Test::Unit::TestCase
|
|
264
264
|
h['e'] = 8
|
265
265
|
h['c'] = 9
|
266
266
|
h['a'] = 10
|
267
|
-
assert_equal '(
|
267
|
+
assert_equal '(f (d (b a c) e) (h g (i - j)))', h.dump_sexp
|
268
268
|
h.delete('d')
|
269
|
-
assert_equal '(
|
269
|
+
assert_equal '(f (b a (e c)) (h g (i - j)))', h.dump_sexp
|
270
270
|
end
|
271
271
|
|
272
272
|
def test_delete_root
|
@@ -582,6 +582,12 @@ class TestRedBlackTree < Test::Unit::TestCase
|
|
582
582
|
assert_equal [1.3, 'a' ], h.first
|
583
583
|
end
|
584
584
|
|
585
|
+
def test_values_for_empty_tree
|
586
|
+
h = RedBlackTree.new
|
587
|
+
|
588
|
+
assert_equal [], h.values
|
589
|
+
end
|
590
|
+
|
585
591
|
if RUBY_VERSION >= '1.9.0'
|
586
592
|
# In contrast to RadixTree, RedBlackTree just uses String#<=> as-is
|
587
593
|
def test_encoding
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: avl_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03-
|
12
|
+
date: 2012-03-27 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email: nahi@ruby-lang.org
|