avl_tree 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/test/helper.rb CHANGED
@@ -5,3 +5,4 @@ rescue LoadError
5
5
  end
6
6
  require "test/unit"
7
7
  require "avl_tree"
8
+ require "red_black_tree"
@@ -0,0 +1,595 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('./helper', File.dirname(__FILE__))
3
+
4
+ class TestRedBlackTree < Test::Unit::TestCase
5
+ def __test_random
6
+ h = RedBlackTree.new
7
+ 10000.times do |idx|
8
+ key = rand(100)
9
+ h[key] = key
10
+ key = rand(100)
11
+ h.delete(key)
12
+ end
13
+ end
14
+
15
+ def test_tree_rotate_RR
16
+ h = RedBlackTree.new
17
+ assert_equal '', h.dump_sexp
18
+ h['a'] = 1
19
+ assert_equal 'a', h.dump_sexp
20
+ h['b'] = 2
21
+ assert_equal '(a - b)', h.dump_sexp
22
+ h['c'] = 3
23
+ assert_equal '(b a c)', h.dump_sexp
24
+ h['d'] = 4
25
+ assert_equal '(b a (c - d))', h.dump_sexp
26
+ h['e'] = 5
27
+ assert_equal '(b a (d c e))', h.dump_sexp
28
+ end
29
+
30
+ def test_tree_rotate_LL
31
+ h = RedBlackTree.new
32
+ h['e'] = 1
33
+ h['d'] = 2
34
+ assert_equal '(e d)', h.dump_sexp
35
+ h['c'] = 3
36
+ assert_equal '(d c e)', h.dump_sexp
37
+ h['b'] = 4
38
+ assert_equal '(d (c b) e)', h.dump_sexp
39
+ h['a'] = 5
40
+ assert_equal '(d (b a c) e)', h.dump_sexp
41
+ end
42
+
43
+ def test_tree_rotate_RL
44
+ h = RedBlackTree.new
45
+ h['b'] = 1
46
+ h['a'] = 2
47
+ h['g'] = 3
48
+ h['d'] = 4
49
+ h['h'] = 5
50
+ assert_equal '(b a (g d h))', h.dump_sexp
51
+ h['c'] = 6
52
+ assert_equal '(b a (g (d c) h))', h.dump_sexp
53
+ h['e'] = 6
54
+ assert_equal '(b a (g (d c e) h))', h.dump_sexp
55
+ h['f'] = 6
56
+ assert_equal '(d (b a c) (g (e - f) h))', h.dump_sexp
57
+ end
58
+
59
+ def test_tree_rotate_LR
60
+ h = RedBlackTree.new
61
+ h['g'] = 1
62
+ h['b'] = 2
63
+ h['h'] = 3
64
+ h['i'] = 4
65
+ h['a'] = 5
66
+ h['d'] = 6
67
+ h['0'] = 7
68
+ h['c'] = 8
69
+ h['e'] = 9
70
+ assert_equal '(g (b (a 0) (d c e)) (h - i))', h.dump_sexp
71
+ h['f'] = 10
72
+ assert_equal '(d (b (a 0) c) (g (e - f) (h - i)))', h.dump_sexp
73
+ end
74
+
75
+ def test_aref_nil
76
+ h = RedBlackTree.new
77
+ h['abc'] = 1
78
+ assert_equal nil, h['def']
79
+ end
80
+
81
+ def test_empty
82
+ h = RedBlackTree.new
83
+ h['abc'] = 0
84
+ assert_equal nil, h['']
85
+ h[''] = 1
86
+ assert_equal 1, h['']
87
+ h.delete('')
88
+ assert_equal nil, h['']
89
+ end
90
+
91
+ def test_aref_single
92
+ h = RedBlackTree.new
93
+ h['abc'] = 1
94
+ assert_equal 1, h['abc']
95
+ end
96
+
97
+ def test_aref_double
98
+ h = RedBlackTree.new
99
+ h['abc'] = 1
100
+ h['def'] = 2
101
+ assert_equal 1, h['abc']
102
+ assert_equal 2, h['def']
103
+ end
104
+
105
+ def test_aset_override
106
+ h = RedBlackTree.new
107
+ h['abc'] = 1
108
+ h['abc'] = 2
109
+ assert_equal 2, h['abc']
110
+ end
111
+
112
+ def test_split
113
+ h = RedBlackTree.new
114
+ h['abcd'] = 1
115
+ assert_equal 1, h['abcd']
116
+ h['abce'] = 2
117
+ assert_equal 1, h['abcd']
118
+ assert_equal 2, h['abce']
119
+ h['abd'] = 3
120
+ assert_equal 1, h['abcd']
121
+ assert_equal 2, h['abce']
122
+ assert_equal 3, h['abd']
123
+ h['ac'] = 4
124
+ assert_equal 1, h['abcd']
125
+ assert_equal 2, h['abce']
126
+ assert_equal 3, h['abd']
127
+ assert_equal 4, h['ac']
128
+ end
129
+
130
+ def test_split_and_assign
131
+ h = RedBlackTree.new
132
+ h['ab'] = 1
133
+ h['a'] = 2
134
+ assert_equal 1, h['ab']
135
+ assert_equal 2, h['a']
136
+ end
137
+
138
+ def test_push
139
+ h = RedBlackTree.new
140
+ assert_equal 0, h.size
141
+ h['a'] = 1
142
+ assert_equal 1, h['a']
143
+ h['ab'] = 2
144
+ assert_equal 1, h['a']
145
+ assert_equal 2, h['ab']
146
+ h['abc'] = 3
147
+ assert_equal 1, h['a']
148
+ assert_equal 2, h['ab']
149
+ assert_equal 3, h['abc']
150
+ h['abd'] = 4
151
+ assert_equal 1, h['a']
152
+ assert_equal 2, h['ab']
153
+ assert_equal 3, h['abc']
154
+ assert_equal 4, h['abd']
155
+ h['ac'] = 5
156
+ assert_equal 1, h['a']
157
+ assert_equal 2, h['ab']
158
+ assert_equal 3, h['abc']
159
+ assert_equal 4, h['abd']
160
+ assert_equal 5, h['ac']
161
+ h['b'] = 6
162
+ assert_equal 1, h['a']
163
+ assert_equal 2, h['ab']
164
+ assert_equal 3, h['abc']
165
+ assert_equal 4, h['abd']
166
+ assert_equal 5, h['ac']
167
+ assert_equal 6, h['b']
168
+ assert_equal ['a', 'ab', 'abc', 'abd', 'ac', 'b'].sort, h.keys.sort
169
+ assert_equal 6, h.size
170
+ end
171
+
172
+ def test_delete_leaf
173
+ h = RedBlackTree.new
174
+ h['b'] = 1
175
+ h['a'] = 2
176
+ h['c'] = 3
177
+ assert_equal 2, h['a']
178
+ h.delete('a')
179
+ assert_equal nil, h['a']
180
+ end
181
+
182
+ def test_delete_leaf_single_rotation
183
+ h = RedBlackTree.new
184
+ h['b'] = 1
185
+ h['a'] = 2
186
+ h['d'] = 3
187
+ h['c'] = 4
188
+ h['e'] = 5
189
+ assert_equal '(b a (d c e))', h.dump_sexp
190
+ h.delete('a')
191
+ assert_equal '(d (b - c) e)', h.dump_sexp
192
+ end
193
+
194
+ def test_delete_leaf_single_rotation_right
195
+ h = RedBlackTree.new
196
+ h['d'] = 1
197
+ h['e'] = 2
198
+ h['b'] = 3
199
+ h['c'] = 4
200
+ h['a'] = 5
201
+ assert_equal '(d (b a c) e)', h.dump_sexp
202
+ h.delete('e')
203
+ assert_equal '(b a (d c))', h.dump_sexp
204
+ end
205
+
206
+ def test_delete_leaf_double_rotation
207
+ h = RedBlackTree.new
208
+ h['b'] = 1
209
+ h['a'] = 2
210
+ h['e'] = 3
211
+ h['0'] = 4
212
+ h['c'] = 5
213
+ h['f'] = 6
214
+ h['d'] = 7
215
+ assert_equal '(b (a 0) (e (c - d) f))', h.dump_sexp
216
+ h.delete('0')
217
+ assert_equal '(b a (e (c - d) f))', h.dump_sexp
218
+ h.delete('a')
219
+ assert_equal '(e (c b d) f)', h.dump_sexp
220
+ end
221
+
222
+ def test_delete_leaf_double_rotation_right
223
+ h = RedBlackTree.new
224
+ h['d'] = 1
225
+ h['e'] = 2
226
+ h['a'] = 3
227
+ h['f'] = 4
228
+ h['c'] = 5
229
+ h['0'] = 6
230
+ h['b'] = 7
231
+ assert_equal '(d (a 0 (c b)) (e - f))', h.dump_sexp
232
+ h.delete('f')
233
+ assert_equal '(d (a 0 (c b)) e)', h.dump_sexp
234
+ h.delete('e')
235
+ assert_equal '(a 0 (c b d))', h.dump_sexp
236
+ end
237
+
238
+ def test_delete_node_right
239
+ h = RedBlackTree.new
240
+ h['c'] = 1
241
+ h['b'] = 2
242
+ h['g'] = 3
243
+ h['a'] = 4
244
+ h['e'] = 5
245
+ h['i'] = 6
246
+ h['d'] = 7
247
+ h['f'] = 8
248
+ h['h'] = 9
249
+ h['j'] = 10
250
+ assert_equal '(c (b a) (g (e d f) (i h j)))', h.dump_sexp
251
+ h.delete('g')
252
+ assert_equal '(c (b a) (h (e d f) (i - j)))', h.dump_sexp
253
+ end
254
+
255
+ def test_delete_node_left
256
+ h = RedBlackTree.new
257
+ h['h'] = 1
258
+ h['i'] = 2
259
+ h['d'] = 3
260
+ h['j'] = 4
261
+ h['f'] = 5
262
+ h['b'] = 6
263
+ h['g'] = 7
264
+ h['e'] = 8
265
+ h['c'] = 9
266
+ h['a'] = 10
267
+ assert_equal '(h (d (b a c) (f e g)) (i - j))', h.dump_sexp
268
+ h.delete('d')
269
+ assert_equal '(h (e (b a c) (f - g)) (i - j))', h.dump_sexp
270
+ end
271
+
272
+ def test_delete_root
273
+ h = RedBlackTree.new
274
+ h['b'] = 1
275
+ h['a'] = 2
276
+ h['c'] = 3
277
+ assert_equal 1, h['b']
278
+ assert_equal '(b a c)', h.dump_sexp
279
+ h.delete('b')
280
+ assert_equal '(c a)', h.dump_sexp
281
+ assert_equal nil, h['b']
282
+ end
283
+
284
+ def test_delete
285
+ h = RedBlackTree.new
286
+ h['a'] = 1
287
+ h['ab'] = 2
288
+ h['abc'] = 3
289
+ h['abd'] = 4
290
+ h['ac'] = 5
291
+ h['b'] = 6
292
+ assert_equal 6, h.size
293
+ assert_equal nil, h.delete('XXX')
294
+ # delete leaf
295
+ assert_equal 4, h.delete('abd')
296
+ assert_equal 5, h.size
297
+ assert_equal 1, h['a']
298
+ assert_equal 2, h['ab']
299
+ assert_equal 3, h['abc']
300
+ assert_equal nil, h['abd']
301
+ assert_equal 5, h['ac']
302
+ assert_equal 6, h['b']
303
+ # delete single leaf node
304
+ assert_equal 2, h.delete('ab')
305
+ assert_equal 4, h.size
306
+ assert_equal 1, h['a']
307
+ assert_equal nil, h['ab']
308
+ assert_equal 3, h['abc']
309
+ assert_equal nil, h['abd']
310
+ assert_equal 5, h['ac']
311
+ assert_equal 6, h['b']
312
+ # delete multiple leaf node
313
+ assert_equal 1, h.delete('a')
314
+ assert_equal 3, h.size
315
+ assert_equal nil, h['a']
316
+ assert_equal nil, h['ab']
317
+ assert_equal 3, h['abc']
318
+ assert_equal nil, h['abd']
319
+ assert_equal 5, h['ac']
320
+ assert_equal 6, h['b']
321
+ assert_equal ['abc', 'ac', 'b'].sort, h.keys.sort
322
+ # delete rest
323
+ assert_equal 3, h.delete('abc')
324
+ assert_equal 5, h.delete('ac')
325
+ assert_equal 6, h.delete('b')
326
+ assert_equal 0, h.size
327
+ assert h.empty?
328
+ end
329
+
330
+ def test_delete_right
331
+ h = RedBlackTree.new
332
+ h['f'] = 1
333
+ h['e'] = 2
334
+ h['d'] = 3
335
+ h['c'] = 4
336
+ h['b'] = 5
337
+ h['a'] = 6
338
+ assert_equal 6, h.size
339
+ assert_equal nil, h.delete('XXX')
340
+ # delete leaf
341
+ assert_equal 4, h.delete('c')
342
+ assert_equal 5, h.size
343
+ assert_equal 1, h['f']
344
+ assert_equal 2, h['e']
345
+ assert_equal 3, h['d']
346
+ assert_equal nil, h['c']
347
+ assert_equal 5, h['b']
348
+ assert_equal 6, h['a']
349
+ # delete single leaf node
350
+ assert_equal 2, h.delete('e')
351
+ assert_equal 4, h.size
352
+ assert_equal 1, h['f']
353
+ assert_equal nil, h['e']
354
+ assert_equal 3, h['d']
355
+ assert_equal nil, h['c']
356
+ assert_equal 5, h['b']
357
+ assert_equal 6, h['a']
358
+ # delete multiple leaf node
359
+ assert_equal 1, h.delete('f')
360
+ assert_equal 3, h.size
361
+ assert_equal nil, h['f']
362
+ assert_equal nil, h['e']
363
+ assert_equal 3, h['d']
364
+ assert_equal nil, h['c']
365
+ assert_equal 5, h['b']
366
+ assert_equal 6, h['a']
367
+ assert_equal ['a', 'b', 'd'].sort, h.keys.sort
368
+ # delete rest
369
+ assert_equal 3, h.delete('d')
370
+ assert_equal 5, h.delete('b')
371
+ assert_equal 6, h.delete('a')
372
+ assert_equal 0, h.size
373
+ assert h.empty?
374
+ end
375
+
376
+ def test_delete_compaction_middle
377
+ h = RedBlackTree.new
378
+ h['a'] = 1
379
+ h['abc'] = 2
380
+ h['bb'] = 3
381
+ h['abcdefghi'] = 4
382
+ h['abcdefghijzz'] = 5
383
+ h['abcdefghikzz'] = 6
384
+ assert_equal 6, h.dump_tree.split($/).size
385
+ h.delete('a')
386
+ assert_equal 5, h.dump_tree.split($/).size
387
+ h['a'] = 1
388
+ assert_equal 6, h.dump_tree.split($/).size
389
+ end
390
+
391
+ def test_delete_compaction_leaf
392
+ h = RedBlackTree.new
393
+ h['a'] = 1
394
+ h['abc'] = 2
395
+ h['bb'] = 3
396
+ h['abcdefghijzz'] = 4
397
+ assert_equal 4, h.dump_tree.split($/).size
398
+ h['abcdefghikzz'] = 5
399
+ assert_equal 5, h.dump_tree.split($/).size
400
+ h.delete('abcdefghijzz')
401
+ assert_equal 4, h.dump_tree.split($/).size
402
+ h['abcdefghijzz'] = 4
403
+ assert_equal 5, h.dump_tree.split($/).size
404
+ end
405
+
406
+ def test_delete_balanced_rotate_left
407
+ h = RedBlackTree.new
408
+ h['f'] = 1
409
+ h['c'] = 100
410
+ h['l'] = 1
411
+ h['b'] = 100
412
+ h['e'] = 1
413
+ h['i'] = 1
414
+ h['m'] = 1
415
+ h['a'] = 100
416
+ h['d'] = 1
417
+ h['h'] = 1
418
+ h['k'] = 1
419
+ h['n'] = 1
420
+ h['j'] = 1
421
+ h['g'] = 1
422
+ assert_equal '(f (c (b a) (e d)) (l (i (h g) (k j)) (m - n)))', h.dump_sexp
423
+ assert_equal 14, h.size
424
+ # reduce black from the left node
425
+ assert_equal 100, h.delete('b')
426
+ assert_equal 100, h.delete('a')
427
+ # double rotation at 'l' and 'f' node
428
+ assert_equal 100, h.delete('c')
429
+ assert_equal 11, h.size
430
+ assert_equal '(i (f (d - e) (h g)) (l (k j) (m - n)))', h.dump_sexp
431
+ end
432
+
433
+ def test_delete_balanced_rotate_right
434
+ h = RedBlackTree.new
435
+ h['i'] = 1
436
+ h['l'] = 100
437
+ h['c'] = 1
438
+ h['m'] = 100
439
+ h['j'] = 1
440
+ h['f'] = 1
441
+ h['b'] = 1
442
+ h['n'] = 100
443
+ h['k'] = 1
444
+ h['g'] = 1
445
+ h['d'] = 1
446
+ h['a'] = 1
447
+ h['e'] = 1
448
+ h['h'] = 1
449
+ assert_equal '(i (c (b a) (f (d - e) (g - h))) (l (j - k) (m - n)))', h.dump_sexp
450
+ assert_equal 14, h.size
451
+ # reduce black from the left node
452
+ assert_equal 100, h.delete('m')
453
+ assert_equal 100, h.delete('n')
454
+ # double rotation at 'c' and 'i' node
455
+ assert_equal 100, h.delete('l')
456
+ assert_equal 11, h.size
457
+ assert_equal '(f (c (b a) (d - e)) (i (g - h) (k j)))', h.dump_sexp
458
+ end
459
+
460
+ def test_each
461
+ h = RedBlackTree.new
462
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6 }
463
+ s.each do |k, v|
464
+ h[k] = v
465
+ end
466
+ assert_equal s.to_a.sort_by { |k, v| k }, h.each.sort_by { |k, v| k }
467
+ #
468
+ values = []
469
+ h.each do |k, v|
470
+ values << [k, v]
471
+ end
472
+ assert_equal s.to_a.sort_by { |k, v| k }, values.sort_by { |k, v| k }
473
+ end
474
+
475
+ def test_each_key
476
+ h = RedBlackTree.new
477
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6 }
478
+ s.each do |k, v|
479
+ h[k] = v
480
+ end
481
+ assert_equal s.keys.sort, h.each_key.sort
482
+ #
483
+ values = []
484
+ h.each_key do |k|
485
+ values << k
486
+ end
487
+ assert_equal s.keys.sort, values.sort
488
+ end
489
+
490
+ def test_each_value
491
+ h = RedBlackTree.new
492
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6, 'azzzzz' => 6 }
493
+ s.each do |k, v|
494
+ h[k] = v
495
+ end
496
+ assert_equal s.values.sort, h.each_value.sort
497
+ #
498
+ values = []
499
+ h.each_value do |v|
500
+ values << v
501
+ end
502
+ assert_equal s.values.sort, values.sort
503
+ end
504
+
505
+ def test_keys
506
+ h = RedBlackTree.new
507
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6 }
508
+ s.each do |k, v|
509
+ h[k] = v
510
+ end
511
+ assert_equal s.keys.sort, h.keys.sort
512
+ end
513
+
514
+ def test_values
515
+ h = RedBlackTree.new
516
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6 }
517
+ s.each do |k, v|
518
+ h[k] = v
519
+ end
520
+ assert_equal s.values.sort, h.values.sort
521
+ end
522
+
523
+ def test_to_s
524
+ h = RedBlackTree.new
525
+ h[:abc] = 1
526
+ assert_equal 1, h["abc"]
527
+ assert_equal 1, h[:abc]
528
+ end
529
+
530
+ def test_key?
531
+ h = RedBlackTree.new
532
+ assert !h.key?('a')
533
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6 }
534
+ s.each do |k, v|
535
+ h[k] = v
536
+ end
537
+ assert h.key?('a')
538
+ end
539
+
540
+ def test_default
541
+ assert_raise(ArgumentError) do
542
+ RedBlackTree.new('both') { :not_allowed }
543
+ end
544
+
545
+ h = RedBlackTree.new('abc')
546
+ assert_equal 'abc', h['foo']
547
+ assert_equal 'abc', h['bar']
548
+ assert h['baz'].object_id == h['qux'].object_id
549
+
550
+ h = RedBlackTree.new { [1, 2] }
551
+ assert_equal [1, 2], h['foo']
552
+ assert_equal [1, 2], h['bar']
553
+ assert h['baz'].object_id != h['qux'].object_id
554
+ end
555
+
556
+ def test_to_hash
557
+ h = RedBlackTree.new
558
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6 }
559
+ s.each do |k, v|
560
+ h[k] = v
561
+ end
562
+ assert_equal s, h.to_hash
563
+ end
564
+
565
+ def test_clear
566
+ h = RedBlackTree.new
567
+ s = { 'aa' => 1, 'ab' => 2, 'bb' => 3, 'bc' => 4, 'a' => 5, 'abc' => 6 }
568
+ s.each do |k, v|
569
+ h[k] = v
570
+ end
571
+ assert_equal s, h.to_hash
572
+ h.clear
573
+ assert_equal 0, h.size
574
+ assert h.to_hash.empty?
575
+ end
576
+
577
+ if RUBY_VERSION >= '1.9.0'
578
+ # In contrast to RadixTree, RedBlackTree just uses String#<=> as-is
579
+ def test_encoding
580
+ h = RedBlackTree.new
581
+ s = { '$B$"$"(B' => 1, '$B$"$$(B' => 2, '$B$$$$(B' => 3, '$B$$$&(B' => 4, '$B$"(B' => 5, '$B$"$$$&(B' => 6 }
582
+ s.each do |k, v|
583
+ h[k] = v
584
+ end
585
+ assert_equal 6, h.size
586
+ s.each do |k, v|
587
+ assert_equal v, h[k]
588
+ end
589
+ str = '$B$"$"(B'
590
+ str.force_encoding('US-ASCII')
591
+ # it's nil for RadixTree because RadixTree uses char-to-char comparison
592
+ assert_equal 1, h[str]
593
+ end
594
+ end
595
+ end