binary_search_tree 2.0 → 2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 03a236331048d1d421274964c9bb1f786a2433f8
4
- data.tar.gz: dc1468a43def290f733104a9df3cd23966c80dd5
3
+ metadata.gz: 1146c21c38df640ed4d1660d3628ac131b045f73
4
+ data.tar.gz: 17f900353706322d84eb7d392223350914b65895
5
5
  SHA512:
6
- metadata.gz: 3809ba134072969efddf39f35284abaf407680821c17eab8932d7b05133ef651eb81ae6ff78793a99fe11c28a703f2b8af892305098a7e499e807f5d21d271e6
7
- data.tar.gz: 3edbf53d2331c7629d2aa4dbffac2930ec9aa99a16786cf34a7888f4af1380e7fd53eb947f026da982062cfb6fdb1b378e39490176ad7a1b93e5fca96b40bff5
6
+ metadata.gz: c5938628cedda9f0d9292c54fd5f45e93df32a2bcb226e5ec078c5dd53f79a76e9893423a2e26d9dbac9ea9ed6faff7dd4464f05e73974cf97f2270114b65ec7
7
+ data.tar.gz: 90bb4aff76e0097329279cd832a1af1f6b936a1a7be34e3f3ea72be5c13b58a900dcf3a7edbb0bd8cea542671ea774673f76fa450978d91bdd8e42000a043bae
@@ -0,0 +1 @@
1
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in conversocial.gemspec
4
+ gemspec
@@ -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
+
@@ -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
@@ -1,522 +1,4 @@
1
- require 'active_support/core_ext/object/blank'
2
- class BinaryNode
3
- attr_accessor :height, :parent, :left, :right, :key, :value
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'