salgo 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/salgo/btree.rb +529 -0
  2. data/tests/btree_test.rb +238 -0
  3. metadata +86 -0
@@ -0,0 +1,529 @@
1
+ #
2
+ # The MIT License
3
+ #
4
+ # Copyright (c) 2010 Samuel R. Baskinger
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #
24
+
25
+ module Salgo
26
+
27
+ class Btree
28
+
29
+ class Node
30
+ attr_reader :keys, :nodes
31
+ attr_writer :keys, :nodes
32
+
33
+ def initialize()
34
+ @keys = []
35
+ @nodes = []
36
+ end
37
+
38
+ # Assume we have enough space to insert in the node.
39
+ # If two sub-trees are specified, it is assumed that they are replacing the subtree
40
+ # that the new_key was in. That sub-tree is replaced with the left_node
41
+ # and the right_node is inserted after the left_node's index.
42
+ def insert(new_key, left_node=nil, right_node=nil)
43
+
44
+ # Caution code.
45
+ throw Exception.new(
46
+ "Both right and left nodes must be nil or defined. One is not: #{right_node} #{left_node}") if (
47
+ right_node.nil? ^ left_node.nil? )
48
+
49
+ insertion_point = 0
50
+
51
+ catch(:foundI) do
52
+ @keys.each_with_index do |node_key, index|
53
+ if ( new_key < node_key )
54
+ insertion_point = index
55
+ throw :foundI
56
+ end
57
+ end
58
+
59
+ insertion_point = @keys.size
60
+ end
61
+
62
+ @keys.insert(insertion_point, new_key)
63
+ @nodes[insertion_point] = left_node if left_node
64
+ @nodes.insert(insertion_point+1, right_node) if right_node
65
+
66
+ end
67
+
68
+ # This node will split itself and return a list of 3 items, [key, left_node, right_node ].
69
+ def split()
70
+
71
+ node_partition = @nodes.size / 2
72
+ key_partition = @keys.size / 2
73
+
74
+ left_node = Node.new()
75
+ right_node = Node.new()
76
+
77
+ left_node.nodes = @nodes[0...node_partition]
78
+ right_node.nodes = @nodes[node_partition..-1]
79
+
80
+ left_node.keys = @keys[0...key_partition]
81
+ right_node.keys = @keys[key_partition+1..-1]
82
+
83
+ [ @keys[key_partition], left_node, right_node ]
84
+ end
85
+
86
+ def leaf?()
87
+ @nodes.size == 0
88
+ end
89
+
90
+ # Similar to find_node_containing_key, but
91
+ # considers keys as they node is iterated through.
92
+ # An array of Salgo::Btree::Node or Salgo::Btree::Key object will be returned with the second element
93
+ # set to the index of the node.
94
+ #
95
+ # If it is a key, then the key holds a match. If a node, then the node
96
+ # subtree that should be expanded and searched.
97
+ def find_node_or_key_containing_key(key)
98
+
99
+ @keys.each_with_index do |node_key, i|
100
+ if ( key == node_key )
101
+ return [ node_key, i ]
102
+ elsif ( key < node_key )
103
+ return [ @nodes[i], i ]
104
+ end
105
+ end
106
+
107
+ return [ @nodes[-1], @nodes.size - 1 ]
108
+ end
109
+
110
+ def find_node_containing_key(key)
111
+ @keys.each_with_index do |node_key, i|
112
+ if ( key < node_key )
113
+ return @nodes[i]
114
+ end
115
+ end
116
+
117
+ # If no throw, we assign the last node because key is bigger (or equal to) all our keys.
118
+ return @nodes[-1]
119
+ end
120
+
121
+ # Return an array of the min-key and min-node from this node.
122
+ # There may or may not be a min-node.
123
+ def take_min()
124
+ [ @keys.shift, @nodes.shift ]
125
+ end
126
+
127
+ def take(index)
128
+ [ @keys.delete_at(index), @nodes.delete_at(index) ]
129
+ end
130
+
131
+ # Return an array of the max-key and the max-node from this node.
132
+ # There may or may not be a max-node.
133
+ def take_max()
134
+ [ @keys.pop, @nodes.pop ]
135
+ end
136
+
137
+ def put_max(key, node)
138
+ @keys.push(key)
139
+ @nodes.push(node) if node
140
+ end
141
+
142
+ def put(index, key, node)
143
+ @keys.insert(index, key)
144
+ @nodes.insert(index, node) if node
145
+ end
146
+
147
+ def put_min(key, node)
148
+ @keys.unshift(key)
149
+ @nodes.unshift(node) if node
150
+ end
151
+
152
+ def last_node?(node)
153
+ @nodes[-1].equal?(node)
154
+ end
155
+
156
+ def first_node?(node)
157
+ @nodes[0].equal?(node)
158
+ end
159
+
160
+ end
161
+
162
+ # The key value should support >, < and ==.
163
+ class Key
164
+ attr_reader :val, :key
165
+ attr_writer :val, :key
166
+
167
+ def initialize(key, val=true)
168
+ @key = key
169
+ @val = val
170
+ end
171
+
172
+ def < (k)
173
+ @key < k.key
174
+ end
175
+
176
+ def > (k)
177
+ @key > k.key
178
+ end
179
+
180
+ def == (k)
181
+ @key == k.key
182
+ end
183
+
184
+ end
185
+
186
+ attr_reader :size
187
+
188
+ def initialize(minnodes=2)
189
+ @minnodes = ( minnodes < 2 )? 2 : minnodes
190
+ @maxnodes = 2 * minnodes
191
+ @root = Node.new()
192
+ @size = 0
193
+ end
194
+
195
+ def root?(node)
196
+ @root.equal? node
197
+ end
198
+
199
+ def full?(node)
200
+ node.keys.size == @maxnodes-1
201
+ end
202
+
203
+ # Does the given node have enough keys (and perhaps nodes) to merge with another node?
204
+ def mergable?(node)
205
+ node.keys.size < @minnodes
206
+ end
207
+
208
+ def has_minimum_keys?(node)
209
+ node.keys.size < @minnodes
210
+ end
211
+
212
+ # Is there an extra key to take, should we need it.
213
+ def has_extra_keys?(node)
214
+ node.keys.size >= @minnodes
215
+ end
216
+
217
+ def split_root
218
+ node = Node.new()
219
+
220
+ node.insert(*@root.split())
221
+
222
+ @root = node
223
+ end
224
+
225
+ # Insert a new value at the given key. Duplicate values are allowed in this data structure
226
+ # and insert does not prevent them. The []= method will replace values.
227
+ def insert(key, val)
228
+ key = Key.new(key, val)
229
+
230
+ # Always make sure our special friend "root" is OK and has room for an insert.
231
+ split_root if full?(@root)
232
+
233
+ parent_node = nil
234
+ node = @root
235
+
236
+ not_inserted = true
237
+
238
+ while(not_inserted)
239
+ if ( full? node )
240
+
241
+ median_key, lnode, rnode = node.split()
242
+
243
+ # NOTE: Because we always split full root nodes, we will never enter here with parent_node=nil
244
+ # Oh good, we can do a normal split and insert the result in the parent.
245
+ parent_node.insert(median_key, lnode, rnode)
246
+
247
+ if ( key < median_key )
248
+ node = lnode
249
+ else
250
+ node = rnode
251
+ end
252
+ end
253
+
254
+ # Can we insert?
255
+ if ( node.leaf? )
256
+ node.insert(key)
257
+ @size += 1
258
+ not_inserted = false
259
+ else
260
+ # which node to examine?
261
+ parent_node = node
262
+ node = node.find_node_containing_key(key)
263
+ end
264
+ end
265
+ end
266
+
267
+ def find_key(key)
268
+
269
+ node = @root
270
+
271
+ candidate, candidate_idx = node.find_node_or_key_containing_key(key)
272
+
273
+ while( ! candidate.nil?)
274
+ if ( candidate.is_a?(Key) )
275
+
276
+ return candidate
277
+ end
278
+
279
+ node = candidate
280
+ candidate, candidate_idx = node.find_node_or_key_containing_key(key)
281
+ end
282
+
283
+ return nil
284
+ end
285
+
286
+ def find(key)
287
+ k = find_key(Key.new(key, nil))
288
+
289
+ (k.nil?) ? nil : k.val
290
+ end
291
+
292
+ # Given the parent node and the child_index of a child node,
293
+ # this method will merge with the sibling to the left of the
294
+ # child. The resulting "unknown" tree will be placed on
295
+ # the left and the known-filled node will be placed in the child
296
+ # node's current spot.
297
+ # The new target node is returned.
298
+ def merge_with_left(parent, child_index)
299
+
300
+ child = parent.nodes[child_index]
301
+ sibling = parent.nodes[child_index-1]
302
+ node = Node.new()
303
+
304
+ node.nodes = sibling.nodes + child.nodes
305
+
306
+ node.keys = sibling.keys + [ parent.keys[child_index-1] ] + child.keys
307
+ parent.take(child_index-1)
308
+ parent.nodes[child_index-1] = node
309
+ node
310
+ end
311
+
312
+ # Same as merge_with_right, but the roles are reversed as
313
+ # are the locations of the resulting subtrees.
314
+ # The new target node is returned.
315
+ def merge_with_right(parent, child_index)
316
+ child = parent.nodes[child_index]
317
+ sibling = parent.nodes[child_index+1]
318
+ node = Node.new()
319
+
320
+ node.nodes = child.nodes + sibling.nodes
321
+
322
+ node.keys = child.keys + [ parent.keys[child_index] ] + sibling.keys
323
+ parent.take(child_index)
324
+ parent.nodes[child_index] = node
325
+ node
326
+ end
327
+
328
+ # Delete from a subtree. We assume the node can withstand delete when called.
329
+ # They key object is returned.
330
+ def delete_max_key(node=@root)
331
+
332
+ return nil if @size == 0
333
+
334
+ if root?(node) and @root.keys.size == 0 and @root.nodes.size == 1
335
+ @root = node = @root.nodes[0]
336
+ end
337
+
338
+ while(true) do
339
+ if ( node.leaf? )
340
+ @size -= 1
341
+ return node.take_max()[0]
342
+ else
343
+
344
+ # Fix up the node before deleting from it.
345
+ if has_minimum_keys?(node.nodes[-1])
346
+ if has_minimum_keys?(node.nodes[-2])
347
+
348
+ node = merge_with_left(node, node.nodes.size-1)
349
+
350
+ else
351
+
352
+ # Pull the max key and node from our "left" sibling.
353
+ # Make the left key be our parent and put the node
354
+ # in the minimum of the right tree node.
355
+ another_key, another_node = node.nodes[-2].take_max
356
+
357
+ node.nodes[-1].put_min(node.keys[-1], another_node)
358
+ node.keys[-1] = another_key
359
+
360
+ node = node.nodes[-1]
361
+
362
+ end
363
+ else
364
+ node = node.nodes[-1]
365
+ end
366
+ end
367
+ end
368
+ end
369
+
370
+ # Delete from a subtree. We assume the node can withstand delete when called.
371
+ # The key object is returned.
372
+ def delete_min_key(node=@root)
373
+
374
+ return nil if @size == 0
375
+
376
+ if root?(node) and @root.keys.size == 0 and @root.nodes.size == 1
377
+ @root = node = @root.nodes[0]
378
+ end
379
+
380
+ while(true) do
381
+ if ( node.leaf? )
382
+ @size -= 1
383
+ return node.take_min()[0]
384
+ else
385
+ # Fix up the node before deleting from it.
386
+ if has_minimum_keys?(node.nodes[0])
387
+ if has_minimum_keys?(node.nodes[1])
388
+ node = merge_with_right(node, 0)
389
+
390
+ else
391
+
392
+ # Pull the min key and node from our "right" sibling.
393
+ # Make the right key be our parent and put the node
394
+ # in the minimum of the right tree node.
395
+ another_key, another_node = node.nodes[1].take_min
396
+
397
+ node.nodes[0].put_max(node.keys[0], another_node)
398
+ node.keys[0] = another_key
399
+
400
+ node = node.nodes[0]
401
+ end
402
+ else
403
+ node = node.nodes[0]
404
+ end
405
+
406
+ end
407
+ end
408
+ end
409
+
410
+ def delete_key(key, node=@root)
411
+
412
+ candidate, candidate_idx = node.find_node_or_key_containing_key(key)
413
+
414
+ return nil if candidate.nil?
415
+
416
+ # Delete from this node.
417
+ if ( candidate.is_a?(Key) )
418
+
419
+ # If it's a simple delete...
420
+ if node.leaf?
421
+ node.keys.delete_at(candidate_idx)
422
+ @size -= 1
423
+ return candidate
424
+ elsif has_extra_keys?(node.nodes[candidate_idx])
425
+ node.keys[candidate_idx] = delete_max_key(node.nodes[candidate_idx])
426
+ return candidate
427
+ elsif has_extra_keys?(node.nodes[candidate_idx+1])
428
+ node.keys[candidate_idx] = delete_min_key(node.nodes[candidate_idx+1])
429
+ return candidate
430
+ else
431
+ node = merge_with_right(node, candidate_idx)
432
+
433
+ # The merge_with_right call left the root with no keys and 1 child node.
434
+ # Replace the root and delete from the root.
435
+ @root = @root.nodes[0] if ( @root.nodes.size == 1 )
436
+
437
+ return delete_key(key, node)
438
+ end
439
+
440
+ elsif candidate.is_a?(Node)
441
+
442
+ # Ensure that the node can sustain a delete BEFORE entering it...
443
+ unless has_extra_keys?(candidate)
444
+
445
+ if ( node.first_node?(candidate) )
446
+ if ( has_extra_keys?(node.nodes[1]))
447
+ another_key, another_node = node.nodes[1].take_min
448
+ candidate.put_max(node.keys[0], another_node)
449
+ node.keys[0] = another_key
450
+ else
451
+ merge_with_right(node, candidate_idx)
452
+ end
453
+ #elsif ( node.last_node?(candidate) )
454
+ else
455
+ if ( has_extra_keys?(node.nodes[candidate_idx-1]) )
456
+ another_key, another_node = node.nodes[candidate_idx-1].take_max
457
+ candidate.put_min(node.keys[candidate_idx-1], another_node)
458
+ node.keys[candidate_idx-1] = another_key
459
+ else
460
+ merge_with_left(node, candidate_idx)
461
+ end
462
+ end
463
+ end
464
+
465
+ # If one of the above merges removed all keys from the root, then there is only 1 node.
466
+ # Promote that node as the root.
467
+ candidate = @root = @root.nodes[0] if ( @root.nodes.size == 1 )
468
+
469
+ delete_key(key, candidate)
470
+ end
471
+ end
472
+
473
+ def delete(key)
474
+
475
+ key = delete_key(Key.new(key))
476
+
477
+ (key.nil?)? nil : key.val
478
+ end
479
+
480
+ alias [] find
481
+
482
+ # Set the key in this tree to the given value.
483
+ # If there is already a value at the given key, it is replaced and the old value is returned.
484
+ # Nil is returned otherwise.
485
+ def []=(key, val)
486
+
487
+ k = find_key(Key.new(key))
488
+
489
+ if ( k.nil? )
490
+ insert(key, val)
491
+ nil
492
+ else
493
+ v = k.val
494
+ k.val = val
495
+ v
496
+ end
497
+ end
498
+
499
+ def each(node=@root, &call)
500
+
501
+ proc_child = ( node.leaf?() )? lambda { |x| } : lambda { |child_node| each(child_node, &call) }
502
+
503
+ index = 0
504
+
505
+
506
+ node.keys.each do |key|
507
+ proc_child.call(node.nodes[index])
508
+
509
+ call.call(key.key, key.val)
510
+
511
+ index+=1
512
+
513
+ end
514
+
515
+ proc_child.call(node.nodes[index])
516
+ end
517
+
518
+ def has_key?(key)
519
+ ! find_key(Key.new(key)).nil?
520
+ end
521
+
522
+ alias member? has_key?
523
+ alias include? has_key?
524
+ alias key? has_key?
525
+
526
+ alias store []=
527
+ end
528
+ end
529
+
@@ -0,0 +1,238 @@
1
+ require 'test/unit'
2
+
3
+ require 'salgo/btree'
4
+
5
+ require 'pp'
6
+
7
+ class BTreeTest < Test::Unit::TestCase
8
+ include Salgo
9
+
10
+ def test_nodeinsert()
11
+ assert(true, "OK")
12
+
13
+ n = Btree::Node.new()
14
+
15
+ begin
16
+ n.insert(1, 2)
17
+ assert(false, "Failed to report undefined right or left subtree.")
18
+ rescue Exception => e
19
+ assert(true, "Caught expected exception.")
20
+ end
21
+
22
+ n.insert(1, 2, 3)
23
+ assert(n.nodes[0] == 2)
24
+ assert(n.nodes[1] == 3)
25
+ assert(! n.nodes[0].nil?)
26
+ end
27
+
28
+ def test_nodesplit()
29
+ n = Btree::Node.new()
30
+ n.nodes = [1,1,3,3]
31
+ n.keys = [1,2,3]
32
+ key, lnode, rnode = n.split()
33
+ assert(key == 2, "Key was #{key}")
34
+ assert(lnode.keys==[1])
35
+ assert(rnode.keys==[3])
36
+ assert(lnode.nodes==[1,1])
37
+ assert(rnode.nodes==[3,3])
38
+
39
+ n2 = Btree::Node.new()
40
+
41
+ n2.insert(*n.split())
42
+
43
+ assert(n2.keys[0]==2)
44
+ assert(n2.nodes[0].keys==[1])
45
+ assert(n2.nodes[1].keys==[3])
46
+ assert(n2.nodes[0].nodes==[1,1])
47
+ assert(n2.nodes[1].nodes==[3,3])
48
+ end
49
+
50
+ def test_find_node_containing_key()
51
+ n = Btree::Node.new()
52
+
53
+ n.keys = [Btree::Key.new(1,1), Btree::Key.new(2,2), Btree::Key.new(3,3)]
54
+ n.nodes = [ Btree::Node.new(), Btree::Node.new(), Btree::Node.new(), Btree::Node.new() ]
55
+
56
+ assert(n.find_node_containing_key(Btree::Key.new(0)).equal? n.nodes[0])
57
+ assert(n.find_node_containing_key(Btree::Key.new(1)).equal? n.nodes[1])
58
+ assert(n.find_node_containing_key(Btree::Key.new(2)).equal? n.nodes[2])
59
+ assert(n.find_node_containing_key(Btree::Key.new(3)).equal? n.nodes[3])
60
+ end
61
+
62
+ def test_split()
63
+ bt = Btree.new()
64
+ bt.insert(1, 1)
65
+ bt.insert(2, 2)
66
+ bt.insert(3, 3)
67
+ rt = bt.instance_variable_get("@root")
68
+
69
+ key, lnode, rnode = rt.split()
70
+
71
+ assert(key.val == 2)
72
+ assert(lnode.keys[0].val == 1)
73
+ assert(rnode.keys[0].val == 3)
74
+ end
75
+
76
+ def test_insert()
77
+ bt = Btree.new()
78
+ bt.insert(1, 'a')
79
+ bt.insert(2, 'b')
80
+ bt.insert(3, 'c')
81
+ bt.insert(4, 'd')
82
+ bt.insert(5, 'e')
83
+ bt.insert(6, 'f')
84
+
85
+ assert(bt.size == 6, "Size was not 5 but #{bt.size}")
86
+
87
+ rt = bt.instance_variable_get("@root")
88
+
89
+ assert(rt.nodes[0].keys[0].key == 1)
90
+ assert(rt.keys[0].key == 2)
91
+ assert(rt.nodes[1].keys[0].key == 3)
92
+ assert(rt.keys[1].key == 4)
93
+ assert(rt.nodes[2].keys[0].key == 5)
94
+ assert(rt.nodes[2].keys[1].key == 6)
95
+
96
+ assert(bt.find(1) == 'a')
97
+ assert(bt.find(2) == 'b')
98
+ assert(bt.find(3) == 'c')
99
+ assert(bt.find(4) == 'd')
100
+ assert(bt.find(5) == 'e')
101
+ assert(bt.find(6) == 'f')
102
+ end
103
+
104
+ def test_delete_max_key()
105
+ bt = Btree.new()
106
+ bt.insert(1, 'a')
107
+ bt.insert(2, 'b')
108
+ bt.insert(3, 'c')
109
+ bt.insert(4, 'd')
110
+ bt.insert(5, 'e')
111
+ bt.insert(6, 'f')
112
+
113
+ assert(bt.size == 6, "Size was not 5 but #{bt.size}")
114
+
115
+ assert(bt.delete_max_key().val == 'f')
116
+ assert(bt.delete_max_key().val == 'e')
117
+ assert(bt.delete_max_key().val == 'd')
118
+ assert(bt.delete_max_key().val == 'c')
119
+ assert(bt.delete_max_key().val == 'b')
120
+ assert(bt.delete_max_key().val == 'a')
121
+ assert(bt.size == 0)
122
+ assert(bt.delete_max_key() == nil)
123
+ assert(bt.size == 0)
124
+
125
+ rt = bt.instance_variable_get("@root")
126
+
127
+ end
128
+
129
+ def test_delete_min_key()
130
+ bt = Btree.new()
131
+ bt.insert(1, 'a')
132
+ bt.insert(2, 'b')
133
+ bt.insert(3, 'c')
134
+ bt.insert(4, 'd')
135
+ bt.insert(5, 'e')
136
+ bt.insert(6, 'f')
137
+
138
+ assert(bt.size == 6, "Size was not 5 but #{bt.size}")
139
+ assert(bt.delete_min_key().val == 'a')
140
+ assert(bt.delete_min_key().val == 'b')
141
+ assert(bt.delete_min_key().val == 'c')
142
+ assert(bt.delete_min_key().val == 'd')
143
+ assert(bt.delete_min_key().val == 'e')
144
+ assert(bt.delete_min_key().val == 'f')
145
+ assert(bt.size == 0)
146
+ assert(bt.delete_min_key() == nil)
147
+ assert(bt.size == 0)
148
+
149
+ rt = bt.instance_variable_get("@root")
150
+
151
+ end
152
+
153
+ def test_delete_from_root()
154
+ bt = Btree.new()
155
+ bt.insert(1, 'a')
156
+ bt.insert(2, 'b')
157
+ bt.insert(3, 'c')
158
+ bt.insert(4, 'd')
159
+ bt.insert(5, 'e')
160
+ bt.insert(6, 'f')
161
+
162
+ assert(bt.delete(2)=='b')
163
+ assert(bt.delete(3)=='c')
164
+ assert(bt.delete(1)=='a')
165
+ assert(bt.delete(4)=='d')
166
+
167
+ rt = bt.instance_variable_get("@root")
168
+ assert(bt.size == 2)
169
+ assert(rt.nodes.size == 0)
170
+ assert(rt.keys.size == 2)
171
+ end
172
+
173
+ def test_list_add_remove()
174
+ bt = Btree.new()
175
+
176
+ added_items = [975, 801, 916, 648, 259, 103, 212, 230, 336, 371]
177
+
178
+ added_items.each do |r|
179
+ bt.insert(r, r)
180
+ end
181
+
182
+ assert(bt.size == added_items.size)
183
+
184
+ added_items.each do |k|
185
+ prev_size = bt.size
186
+ assert(bt.delete(k) == k)
187
+ assert(bt.size == prev_size -1)
188
+ end
189
+ end
190
+
191
+ def test_random_add_remove()
192
+ bt = Btree.new()
193
+
194
+ added_items = []
195
+
196
+ sz = 10
197
+ sz.times do
198
+ r = (rand * 1000).to_i
199
+ added_items << r
200
+ bt.insert(r, r)
201
+ end
202
+
203
+ assert(bt.size == sz)
204
+
205
+ added_items.each do |k|
206
+ prev_size = bt.size
207
+ assert(bt.delete(k) == k)
208
+ assert(bt.size == prev_size -1)
209
+ end
210
+ end
211
+
212
+ def test_adds()
213
+ bt = Btree.new()
214
+
215
+ bt[1] = 1
216
+ bt[1] = 'a'
217
+
218
+ assert(bt[1] == 'a')
219
+ end
220
+
221
+ def test_each()
222
+
223
+ i = 0
224
+
225
+ bt = Btree.new()
226
+ bt.insert(1, 'a')
227
+ bt.insert(2, 'b')
228
+ bt.insert(3, 'c')
229
+ bt.insert(4, 'd')
230
+ bt.insert(5, 'e')
231
+ bt.insert(6, 'f')
232
+
233
+ bt.each { |k,v| i+=1 }
234
+
235
+ assert(i == bt.size)
236
+
237
+ end
238
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: salgo
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Sam Baskinger
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-02 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: log4r
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 29
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 5
34
+ version: 1.0.5
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: A collection of algorithms and datastructure for ruby written in ruby.
38
+ email: basking2@rubyforge.org.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - lib/salgo/btree.rb
47
+ - tests/btree_test.rb
48
+ has_rdoc: true
49
+ homepage: http://salgo.rubyforge.org
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 31
63
+ segments:
64
+ - 1
65
+ - 6
66
+ - 8
67
+ version: 1.6.8
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project: http://salgo.rubyforge.org/
80
+ rubygems_version: 1.3.7
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: simply algorithms
84
+ test_files:
85
+ - tests/btree_test.rb
86
+ - tests/btree_test.rb