stakach-algorithms 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README.markdown +99 -97
  2. data/Rakefile +15 -27
  3. data/ext/algorithms/string/extconf.rb +4 -4
  4. data/ext/algorithms/string/string.c +68 -70
  5. data/ext/containers/bst/bst.c +249 -249
  6. data/ext/containers/bst/extconf.rb +4 -4
  7. data/ext/containers/deque/deque.c +248 -248
  8. data/ext/containers/deque/extconf.rb +4 -4
  9. data/ext/containers/rbtree_map/extconf.rb +4 -4
  10. data/ext/containers/rbtree_map/rbtree.c +500 -500
  11. data/ext/containers/splaytree_map/extconf.rb +4 -4
  12. data/ext/containers/splaytree_map/splaytree.c +421 -421
  13. data/lib/algorithms.rb +69 -69
  14. data/lib/algorithms/search.rb +85 -85
  15. data/lib/algorithms/sort.rb +242 -242
  16. data/lib/algorithms/string.rb +10 -10
  17. data/lib/algorithms/version.rb +3 -3
  18. data/lib/containers/deque.rb +176 -176
  19. data/lib/containers/heap.rb +501 -506
  20. data/lib/containers/kd_tree.rb +112 -112
  21. data/lib/containers/priority_queue.rb +116 -116
  22. data/lib/containers/queue.rb +71 -71
  23. data/lib/containers/rb_tree_map.rb +402 -402
  24. data/lib/containers/splay_tree_map.rb +273 -273
  25. data/lib/containers/stack.rb +70 -70
  26. data/lib/containers/suffix_array.rb +71 -71
  27. data/lib/containers/trie.rb +187 -187
  28. data/spec/bst_gc_mark_spec.rb +25 -0
  29. data/spec/bst_spec.rb +25 -0
  30. data/spec/deque_gc_mark_spec.rb +17 -0
  31. data/spec/deque_spec.rb +107 -0
  32. data/spec/heap_spec.rb +130 -0
  33. data/spec/helper.rb +4 -0
  34. data/spec/kd_expected_out.txt +10000 -0
  35. data/spec/kd_test_in.txt +10000 -0
  36. data/spec/kd_tree_spec.rb +33 -0
  37. data/spec/map_gc_mark_spec.rb +28 -0
  38. data/spec/priority_queue_spec.rb +74 -0
  39. data/spec/queue_spec.rb +60 -0
  40. data/spec/rb_tree_map_spec.rb +122 -0
  41. data/spec/search_spec.rb +27 -0
  42. data/spec/sort_spec.rb +26 -0
  43. data/spec/splay_tree_map_spec.rb +105 -0
  44. data/spec/stack_spec.rb +59 -0
  45. data/spec/string_spec.rb +12 -0
  46. data/spec/suffix_array_spec.rb +39 -0
  47. data/spec/trie_spec.rb +58 -0
  48. metadata +60 -4
@@ -1,10 +1,10 @@
1
- =begin rdoc
2
- This module implements string algorithms. Documentation is provided for each algorithm.
3
-
4
- =end
5
-
6
-
7
- begin
8
- require 'CString' unless RUBY_PLATFORM =~ /java/
9
- rescue
10
- end
1
+ =begin rdoc
2
+ This module implements string algorithms. Documentation is provided for each algorithm.
3
+
4
+ =end
5
+
6
+
7
+ begin
8
+ require 'CString' unless RUBY_PLATFORM =~ /java/
9
+ rescue
10
+ end
@@ -1,3 +1,3 @@
1
- module Algorithms
2
- VERSION = "1.0.6"
3
- end
1
+ module Algorithms
2
+ VERSION = "1.0.7"
3
+ end
@@ -1,176 +1,176 @@
1
- =begin rdoc
2
- A Deque is a container that allows items to be added and removed from both the front and back,
3
- acting as a combination of a Stack and Queue.
4
-
5
- This implementation uses a doubly-linked list, guaranteeing O(1) complexity for all operations.
6
- =end
7
- module Algorithms
8
- module Containers
9
- class RubyDeque
10
- include Enumerable
11
-
12
- Node = Struct.new(:left, :right, :obj)
13
-
14
- # Create a new Deque. Takes an optional array argument to initialize the Deque.
15
- #
16
- # d = Containers::Deque.new([1, 2, 3])
17
- # d.front #=> 1
18
- # d.back #=> 3
19
- def initialize(ary=[])
20
- @front = nil
21
- @back = nil
22
- @size = 0
23
- ary.to_a.each { |obj| push_back(obj) }
24
- end
25
-
26
- # Returns true if the Deque is empty, false otherwise.
27
- def empty?
28
- @size == 0
29
- end
30
-
31
- # Removes all the objects in the Deque.
32
- def clear
33
- @front = @back = nil
34
- @size = 0
35
- end
36
-
37
- # Return the number of items in the Deque.
38
- #
39
- # d = Containers::Deque.new([1, 2, 3])
40
- # d.size #=> 3
41
- def size
42
- @size
43
- end
44
- alias_method :length, :size
45
-
46
- # Returns the object at the front of the Deque but does not remove it.
47
- #
48
- # d = Containers::Deque.new
49
- # d.push_front(1)
50
- # d.push_front(2)
51
- # d.front #=> 2
52
- def front
53
- @front && @front.obj
54
- end
55
-
56
- # Returns the object at the back of the Deque but does not remove it.
57
- #
58
- # d = Containers::Deque.new
59
- # d.push_front(1)
60
- # d.push_front(2)
61
- # d.back #=> 1
62
- def back
63
- @back && @back.obj
64
- end
65
-
66
- # Adds an object at the front of the Deque.
67
- #
68
- # d = Containers::Deque.new([1, 2, 3])
69
- # d.push_front(0)
70
- # d.pop_front #=> 0
71
- def push_front(obj)
72
- node = Node.new(nil, nil, obj)
73
- if @front
74
- node.right = @front
75
- @front.left = node
76
- @front = node
77
- else
78
- @front = @back = node
79
- end
80
- @size += 1
81
- obj
82
- end
83
-
84
- # Adds an object at the back of the Deque.
85
- #
86
- # d = Containers::Deque.new([1, 2, 3])
87
- # d.push_back(4)
88
- # d.pop_back #=> 4
89
- def push_back(obj)
90
- node = Node.new(nil, nil, obj)
91
- if @back
92
- node.left = @back
93
- @back.right = node
94
- @back = node
95
- else
96
- @front = @back = node
97
- end
98
- @size += 1
99
- obj
100
- end
101
-
102
- # Returns the object at the front of the Deque and removes it.
103
- #
104
- # d = Containers::Deque.new
105
- # d.push_front(1)
106
- # d.push_front(2)
107
- # d.pop_front #=> 2
108
- # d.size #=> 1
109
- def pop_front
110
- return nil unless @front
111
- node = @front
112
- if @size == 1
113
- clear
114
- return node.obj
115
- else
116
- @front.right.left = nil
117
- @front = @front.right
118
- end
119
- @size -= 1
120
- node.obj
121
- end
122
-
123
- # Returns the object at the back of the Deque and removes it.
124
- #
125
- # d = Containers::Deque.new
126
- # d.push_front(1)
127
- # d.push_front(2)
128
- # d.pop_back #=> 1
129
- # d.size #=> 1
130
- def pop_back
131
- return nil unless @back
132
- node = @back
133
- if @size == 1
134
- clear
135
- return node.obj
136
- else
137
- @back.left.right = nil
138
- @back = @back.left
139
- end
140
- @size -= 1
141
- node.obj
142
- end
143
-
144
- # Iterate over the Deque in FIFO order.
145
- def each_forward
146
- return unless @front
147
- node = @front
148
- while node
149
- yield node.obj
150
- node = node.right
151
- end
152
- end
153
- alias_method :each, :each_forward
154
-
155
- # Iterate over the Deque in LIFO order.
156
- def each_backward
157
- return unless @back
158
- node = @back
159
- while node
160
- yield node.obj
161
- node = node.left
162
- end
163
- end
164
- alias_method :reverse_each, :each_backward
165
-
166
- end
167
- end
168
-
169
- begin
170
- require 'CDeque'
171
- Containers::Deque = Containers::CDeque
172
- rescue Object # C Version could not be found, try ruby version
173
- Containers::Deque = Containers::RubyDeque
174
- end
175
-
176
- end
1
+ =begin rdoc
2
+ A Deque is a container that allows items to be added and removed from both the front and back,
3
+ acting as a combination of a Stack and Queue.
4
+
5
+ This implementation uses a doubly-linked list, guaranteeing O(1) complexity for all operations.
6
+ =end
7
+ module Algorithms
8
+ module Containers
9
+ class RubyDeque
10
+ include Enumerable
11
+
12
+ Node = Struct.new(:left, :right, :obj)
13
+
14
+ # Create a new Deque. Takes an optional array argument to initialize the Deque.
15
+ #
16
+ # d = Containers::Deque.new([1, 2, 3])
17
+ # d.front #=> 1
18
+ # d.back #=> 3
19
+ def initialize(ary=[])
20
+ @front = nil
21
+ @back = nil
22
+ @size = 0
23
+ ary.to_a.each { |obj| push_back(obj) }
24
+ end
25
+
26
+ # Returns true if the Deque is empty, false otherwise.
27
+ def empty?
28
+ @size == 0
29
+ end
30
+
31
+ # Removes all the objects in the Deque.
32
+ def clear
33
+ @front = @back = nil
34
+ @size = 0
35
+ end
36
+
37
+ # Return the number of items in the Deque.
38
+ #
39
+ # d = Containers::Deque.new([1, 2, 3])
40
+ # d.size #=> 3
41
+ def size
42
+ @size
43
+ end
44
+ alias_method :length, :size
45
+
46
+ # Returns the object at the front of the Deque but does not remove it.
47
+ #
48
+ # d = Containers::Deque.new
49
+ # d.push_front(1)
50
+ # d.push_front(2)
51
+ # d.front #=> 2
52
+ def front
53
+ @front && @front.obj
54
+ end
55
+
56
+ # Returns the object at the back of the Deque but does not remove it.
57
+ #
58
+ # d = Containers::Deque.new
59
+ # d.push_front(1)
60
+ # d.push_front(2)
61
+ # d.back #=> 1
62
+ def back
63
+ @back && @back.obj
64
+ end
65
+
66
+ # Adds an object at the front of the Deque.
67
+ #
68
+ # d = Containers::Deque.new([1, 2, 3])
69
+ # d.push_front(0)
70
+ # d.pop_front #=> 0
71
+ def push_front(obj)
72
+ node = Node.new(nil, nil, obj)
73
+ if @front
74
+ node.right = @front
75
+ @front.left = node
76
+ @front = node
77
+ else
78
+ @front = @back = node
79
+ end
80
+ @size += 1
81
+ obj
82
+ end
83
+
84
+ # Adds an object at the back of the Deque.
85
+ #
86
+ # d = Containers::Deque.new([1, 2, 3])
87
+ # d.push_back(4)
88
+ # d.pop_back #=> 4
89
+ def push_back(obj)
90
+ node = Node.new(nil, nil, obj)
91
+ if @back
92
+ node.left = @back
93
+ @back.right = node
94
+ @back = node
95
+ else
96
+ @front = @back = node
97
+ end
98
+ @size += 1
99
+ obj
100
+ end
101
+
102
+ # Returns the object at the front of the Deque and removes it.
103
+ #
104
+ # d = Containers::Deque.new
105
+ # d.push_front(1)
106
+ # d.push_front(2)
107
+ # d.pop_front #=> 2
108
+ # d.size #=> 1
109
+ def pop_front
110
+ return nil unless @front
111
+ node = @front
112
+ if @size == 1
113
+ clear
114
+ return node.obj
115
+ else
116
+ @front.right.left = nil
117
+ @front = @front.right
118
+ end
119
+ @size -= 1
120
+ node.obj
121
+ end
122
+
123
+ # Returns the object at the back of the Deque and removes it.
124
+ #
125
+ # d = Containers::Deque.new
126
+ # d.push_front(1)
127
+ # d.push_front(2)
128
+ # d.pop_back #=> 1
129
+ # d.size #=> 1
130
+ def pop_back
131
+ return nil unless @back
132
+ node = @back
133
+ if @size == 1
134
+ clear
135
+ return node.obj
136
+ else
137
+ @back.left.right = nil
138
+ @back = @back.left
139
+ end
140
+ @size -= 1
141
+ node.obj
142
+ end
143
+
144
+ # Iterate over the Deque in FIFO order.
145
+ def each_forward
146
+ return unless @front
147
+ node = @front
148
+ while node
149
+ yield node.obj
150
+ node = node.right
151
+ end
152
+ end
153
+ alias_method :each, :each_forward
154
+
155
+ # Iterate over the Deque in LIFO order.
156
+ def each_backward
157
+ return unless @back
158
+ node = @back
159
+ while node
160
+ yield node.obj
161
+ node = node.left
162
+ end
163
+ end
164
+ alias_method :reverse_each, :each_backward
165
+
166
+ end
167
+ end
168
+
169
+ begin
170
+ require 'CDeque'
171
+ Containers::Deque = Containers::CDeque
172
+ rescue Object # C Version could not be found, try ruby version
173
+ Containers::Deque = Containers::RubyDeque
174
+ end
175
+
176
+ end
@@ -1,507 +1,502 @@
1
- =begin rdoc
2
- A Heap is a container that satisfies the heap property that nodes are
3
- always smaller in value than their parent node.
4
-
5
- The Algorithms::Containers::Heap class is flexible and upon
6
- initialization, takes an optional block that determines how the items are
7
- ordered. Two versions that are included are the
8
- Algorithms::Containers::MaxHeap and Algorithms::Containers::MinHeap that
9
- return the largest and smallest items on each invocation, respectively.
10
-
11
- This library implements a Fibonacci heap, which allows O(1) complexity for
12
- most methods.
13
- =end
14
- module Algorithms
15
- module Containers
16
- class Heap
17
- include Enumerable
18
-
19
- # call-seq:
20
- # size -> int
21
- #
22
- # Return the number of elements in the heap.
23
- def size
24
- @size
25
- end
26
- alias_method :length, :size
27
-
28
- # call-seq:
29
- # Heap.new(optional_array) { |x, y| optional_comparison_fn }
30
- # -> new_heap
31
- #
32
- # If an optional array is passed, the entries in the array are inserted
33
- # into the heap with equal key and value fields. Also, an optional block
34
- # can be passed to define the function that maintains heap property. For
35
- # example, a min-heap can be created with:
36
- #
37
- # minheap = Heap.new { |x, y| (x <=> y) == -1 }
38
- # minheap.push(6)
39
- # minheap.push(10)
40
- # minheap.pop #=> 6
41
- #
42
- # Thus, smaller elements will be parent nodes. The heap defaults to a
43
- # min-heap if no block is given.
44
- def initialize(ary=[], &block)
45
- @compare_fn = block || lambda { |x, y| (x <=> y) == -1 }
46
- @next = nil
47
- @size = 0
48
- @stored = {}
49
-
50
- ary.each { |n| push(n) } unless ary.empty?
51
- end
52
-
53
- # call-seq:
54
- # push(key, value) -> value
55
- # push(value) -> value
56
- #
57
- # Inserts an item with a given key into the heap. If only one parameter
58
- # is given, the key is set to the value.
59
- #
60
- # Complexity: O(1)
61
- #
62
- # heap = MinHeap.new
63
- # heap.push(1, "Cat")
64
- # heap.push(2)
65
- # heap.pop #=> "Cat"
66
- # heap.pop #=> 2
67
- def push(key, value=key)
68
- raise ArgumentError, "Heap keys must not be nil." unless key
69
- node = Node.new(key, value)
70
- # Add new node to the left of the @next node
71
- if @next
72
- node.right = @next
73
- node.left = @next.left
74
- node.left.right = node
75
- @next.left = node
76
- if @compare_fn[key, @next.key]
77
- @next = node
78
- end
79
- else
80
- @next = node
81
- end
82
- @size += 1
83
-
84
- arr = []
85
- w = @next.right
86
- until w == @next do
87
- arr << w.value
88
- w = w.right
89
- end
90
- arr << @next.value
91
- @stored[key] ||= []
92
- @stored[key] << node
93
- value
94
- end
95
- alias_method :<<, :push
96
-
97
- # call-seq:
98
- # has_key?(key) -> true or false
99
- #
100
- # Returns true if heap contains the key.
101
- #
102
- # Complexity: O(1)
103
- #
104
- # minheap = MinHeap.new([1, 2])
105
- # minheap.has_key?(2) #=> true
106
- # minheap.has_key?(4) #=> false
107
- def has_key?(key)
108
- @stored[key] && !@stored[key].empty? ? true : false
109
- end
110
-
111
- # call-seq:
112
- # next -> value
113
- # next -> nil
114
- #
115
- # Returns the value of the next item in heap order, but does not remove
116
- # it.
117
- #
118
- # Complexity: O(1)
119
- #
120
- # minheap = MinHeap.new([1, 2])
121
- # minheap.next #=> 1
122
- # minheap.size #=> 2
123
- def next
124
- @next && @next.value
125
- end
126
-
127
- # call-seq:
128
- # clear -> nil
129
- #
130
- # Removes all elements from the heap, destructively.
131
- #
132
- # Complexity: O(1)
133
- #
134
- def clear
135
- @next = nil
136
- @size = 0
137
- @stored = {}
138
- nil
139
- end
140
-
141
- # call-seq:
142
- # empty? -> true or false
143
- #
144
- # Returns true if the heap is empty, false otherwise.
145
- def empty?
146
- @next.nil?
147
- end
148
-
149
- # call-seq:
150
- # merge!(otherheap) -> merged_heap
151
- #
152
- # Does a shallow merge of all the nodes in the other heap.
153
- #
154
- # Complexity: O(1)
155
- #
156
- # heap = MinHeap.new([5, 6, 7, 8])
157
- # otherheap = MinHeap.new([1, 2, 3, 4])
158
- # heap.merge!(otherheap)
159
- # heap.size #=> 8
160
- # heap.pop #=> 1
161
- def merge!(otherheap)
162
- raise ArgumentError, "Trying to merge a heap with something not a heap" unless otherheap.kind_of? Heap
163
- other_root = otherheap.instance_variable_get("@next")
164
- if other_root
165
- @stored = @stored.merge(otherheap.instance_variable_get("@stored")) { |key, a, b| (a << b).flatten }
166
- # Insert othernode's @next node to the left of current @next
167
- @next.left.right = other_root
168
- ol = other_root.left
169
- other_root.left = @next.left
170
- ol.right = @next
171
- @next.left = ol
172
-
173
- @next = other_root if @compare_fn[other_root.key, @next.key]
174
- end
175
- @size += otherheap.size
176
- end
177
-
178
- # call-seq:
179
- # pop -> value
180
- # pop -> nil
181
- #
182
- # Returns the value of the next item in heap order and removes it from
183
- # the heap.
184
- #
185
- # Complexity: O(1)
186
- #
187
- # minheap = MinHeap.new([1, 2])
188
- # minheap.pop #=> 1
189
- # minheap.size #=> 1
190
- def pop
191
- return nil unless @next
192
- popped = @next
193
- if @size == 1
194
- clear
195
- return popped.value
196
- end
197
- # Merge the popped's children into root node
198
- if @next.child
199
- @next.child.parent = nil
200
-
201
- # get rid of parent
202
- sibling = @next.child.right
203
- until sibling == @next.child
204
- sibling.parent = nil
205
- sibling = sibling.right
206
- end
207
-
208
- # Merge the children into the root. If @next is the only root node,
209
- # make its child the @next node
210
- if @next.right == @next
211
- @next = @next.child
212
- else
213
- next_left, next_right = @next.left, @next.right
214
- current_child = @next.child
215
- @next.right.left = current_child
216
- @next.left.right = current_child.right
217
- current_child.right.left = next_left
218
- current_child.right = next_right
219
- @next = @next.right
220
- end
221
- else
222
- @next.left.right = @next.right
223
- @next.right.left = @next.left
224
- @next = @next.right
225
- end
226
- consolidate
227
-
228
- unless @stored[popped.key].delete(popped)
229
- raise "Couldn't delete node from stored nodes hash"
230
- end
231
- @size -= 1
232
-
233
- popped.value
234
- end
235
- alias_method :next!, :pop
236
-
237
- # call-seq:
238
- # change_key(key, new_key) -> [new_key, value]
239
- # change_key(key, new_key) -> nil
240
- #
241
- # Changes the key from one to another. Doing so must not violate the
242
- # heap property or an exception will be raised. If the key is found, an
243
- # array containing the new key and value pair is returned, otherwise
244
- # nil is returned.
245
- #
246
- # In the case of duplicate keys, an arbitrary key is changed. This will
247
- # be investigated more in the future.
248
- #
249
- # Complexity: amortized O(1)
250
- #
251
- # minheap = MinHeap.new([1, 2])
252
- # minheap.change_key(2, 3) #=> raise error since we can't increase the value in a min-heap
253
- # minheap.change_key(2, 0) #=> [0, 2]
254
- # minheap.pop #=> 2
255
- # minheap.pop #=> 1
256
- def change_key(key, new_key, delete=false)
257
- return if @stored[key].nil? || @stored[key].empty? || (key == new_key)
258
-
259
- # Must maintain heap property
260
- raise "Changing this key would not maintain heap property!" unless (delete || @compare_fn[new_key, key])
261
- node = @stored[key].shift
262
- if node
263
- node.key = new_key
264
- @stored[new_key] ||= []
265
- @stored[new_key] << node
266
- parent = node.parent
267
- if parent
268
- # if heap property is violated
269
- if delete || @compare_fn[new_key, parent.key]
270
- cut(node, parent)
271
- cascading_cut(parent)
272
- end
273
- end
274
- if delete || @compare_fn[node.key, @next.key]
275
- @next = node
276
- end
277
- return [node.key, node.value]
278
- end
279
- nil
280
- end
281
-
282
- # call-seq:
283
- # delete(key) -> value
284
- # delete(key) -> nil
285
- #
286
- # Deletes the item with associated key and returns it. nil is returned
287
- # if the keyis not found. In the case of nodes with duplicate keys, an
288
- # arbitrary one is deleted.
289
- #
290
- # Complexity: amortized O(log n)
291
- #
292
- # minheap = MinHeap.new([1, 2])
293
- # minheap.delete(1) #=> 1
294
- # minheap.size #=> 1
295
- def delete(key)
296
- pop if change_key(key, nil, true)
297
- end
298
-
299
- # Node class used internally
300
- class Node # :nodoc:
301
- attr_accessor :parent, :child, :left, :right, :key, :value, :degree, :marked
302
-
303
- def initialize(key, value)
304
- @key = key
305
- @value = value
306
- @degree = 0
307
- @marked = false
308
- @right = self
309
- @left = self
310
- end
311
-
312
- def marked?
313
- @marked == true
314
- end
315
-
316
- end
317
-
318
- # make node a child of a parent node
319
- def link_nodes(child, parent)
320
- # link the child's siblings
321
- child.left.right = child.right
322
- child.right.left = child.left
323
-
324
- child.parent = parent
325
-
326
- # if parent doesn't have children, make new child its only child
327
- if parent.child.nil?
328
- parent.child = child.right = child.left = child
329
- else # otherwise insert new child into parent's children list
330
- current_child = parent.child
331
- child.left = current_child
332
- child.right = current_child.right
333
- current_child.right.left = child
334
- current_child.right = child
335
- end
336
- parent.degree += 1
337
- child.marked = false
338
- end
339
- private :link_nodes
340
-
341
- # Makes sure the structure does not contain nodes in the root list with
342
- # equal degrees
343
- def consolidate
344
- roots = []
345
- root = @next
346
- min = root
347
- # find the nodes in the list
348
- loop do
349
- roots << root
350
- root = root.right
351
- break if root == @next
352
- end
353
- degrees = []
354
- roots.each do |root|
355
- min = root if @compare_fn[root.key, min.key]
356
- # check if we need to merge
357
- if degrees[root.degree].nil? # no other node with the same degree
358
- degrees[root.degree] = root
359
- next
360
- else # there is another node with the same degree, consolidate them
361
- degree = root.degree
362
- until degrees[degree].nil? do
363
- other_root_with_degree = degrees[degree]
364
- if @compare_fn[root.key, other_root_with_degree.key] # determine which node is the parent, which one is the child
365
- smaller, larger = root, other_root_with_degree
366
- else
367
- smaller, larger = other_root_with_degree, root
368
- end
369
- link_nodes(larger, smaller)
370
- degrees[degree] = nil
371
- root = smaller
372
- degree += 1
373
- end
374
- degrees[degree] = root
375
- min = root if min.key == root.key # this fixes a bug with duplicate keys not being in the right order
376
- end
377
- end
378
- @next = min
379
- end
380
- private :consolidate
381
-
382
- def cascading_cut(node)
383
- p = node.parent
384
- if p
385
- if node.marked?
386
- cut(node, p)
387
- cascading_cut(p)
388
- else
389
- node.marked = true
390
- end
391
- end
392
- end
393
- private :cascading_cut
394
-
395
- # remove x from y's children and add x to the root list
396
- def cut(x, y)
397
- x.left.right = x.right
398
- x.right.left = x.left
399
- y.degree -= 1
400
- if (y.degree == 0)
401
- y.child = nil
402
- elsif (y.child == x)
403
- y.child = x.right
404
- end
405
- x.right = @next
406
- x.left = @next.left
407
- @next.left = x
408
- x.left.right = x
409
- x.parent = nil
410
- x.marked = false
411
- end
412
- private :cut
413
-
414
- end
415
-
416
- # A MaxHeap is a heap where the items are returned in descending order of
417
- # key value.
418
- class MaxHeap < Heap
419
-
420
- # call-seq:
421
- # MaxHeap.new(ary) -> new_heap
422
- #
423
- # Creates a new MaxHeap with an optional array parameter of items to
424
- # insert into the heap. A MaxHeap is created by calling
425
- # Heap.new { |x, y| (x <=> y) == 1 }, so this is a convenience class.
426
- #
427
- # maxheap = MaxHeap.new([1, 2, 3, 4])
428
- # maxheap.pop #=> 4
429
- # maxheap.pop #=> 3
430
- def initialize(ary=[])
431
- super(ary) { |x, y| (x <=> y) == 1 }
432
- end
433
-
434
- # call-seq:
435
- # max -> value
436
- # max -> nil
437
- #
438
- # Returns the item with the largest key, but does not remove it from the
439
- # heap.
440
- #
441
- # maxheap = MaxHeap.new([1, 2, 3, 4])
442
- # maxheap.max #=> 4
443
- def max
444
- self.next
445
- end
446
-
447
- # call-seq:
448
- # max! -> value
449
- # max! -> nil
450
- #
451
- # Returns the item with the largest key and removes it from the heap.
452
- #
453
- # maxheap = MaxHeap.new([1, 2, 3, 4])
454
- # maxheap.max! #=> 4
455
- # maxheap.size #=> 3
456
- def max!
457
- self.pop
458
- end
459
- end
460
-
461
- # A MinHeap is a heap where the items are returned in ascending order of
462
- # key value.
463
- class MinHeap < Heap
464
-
465
- # call-seq:
466
- # MinHeap.new(ary) -> new_heap
467
- #
468
- # Creates a new MinHeap with an optional array parameter of items to
469
- # insert into the heap.
470
- # A MinHeap is created by calling Heap.new { |x, y| (x <=> y) == -1 },
471
- # so this is a convenience class.
472
- #
473
- # minheap = MinHeap.new([1, 2, 3, 4])
474
- # minheap.pop #=> 1
475
- # minheap.pop #=> 2
476
- def initialize(ary=[])
477
- super(ary) { |x, y| (x <=> y) == -1 }
478
- end
479
-
480
- # call-seq:
481
- # min -> value
482
- # min -> nil
483
- #
484
- # Returns the item with the smallest key, but does not remove it from
485
- # the heap.
486
- #
487
- # minheap = MinHeap.new([1, 2, 3, 4])
488
- # minheap.min #=> 1
489
- def min
490
- self.next
491
- end
492
-
493
- # call-seq:
494
- # min! -> value
495
- # min! -> nil
496
- #
497
- # Returns the item with the smallest key and removes it from the heap.
498
- #
499
- # minheap = MinHeap.new([1, 2, 3, 4])
500
- # minheap.min! #=> 1
501
- # minheap.size #=> 3
502
- def min!
503
- self.pop
504
- end
505
- end
506
- end
1
+ =begin rdoc
2
+ A Heap is a container that satisfies the heap property that nodes are always smaller in
3
+ value than their parent node.
4
+
5
+ The Containers::Heap class is flexible and upon initialization, takes an optional block
6
+ that determines how the items are ordered. Two versions that are included are the
7
+ Containers::MaxHeap and Containers::MinHeap that return the largest and smallest items on
8
+ each invocation, respectively.
9
+
10
+ This library implements a Fibonacci heap, which allows O(1) complexity for most methods.
11
+ =end
12
+ class Containers::Heap
13
+ include Enumerable
14
+
15
+ # call-seq:
16
+ # size -> int
17
+ #
18
+ # Return the number of elements in the heap.
19
+ def size
20
+ @size
21
+ end
22
+ alias_method :length, :size
23
+
24
+ # call-seq:
25
+ # Heap.new(optional_array) { |x, y| optional_comparison_fn } -> new_heap
26
+ #
27
+ # If an optional array is passed, the entries in the array are inserted into the heap with
28
+ # equal key and value fields. Also, an optional block can be passed to define the function
29
+ # that maintains heap property. For example, a min-heap can be created with:
30
+ #
31
+ # minheap = Heap.new { |x, y| (x <=> y) == -1 }
32
+ # minheap.push(6)
33
+ # minheap.push(10)
34
+ # minheap.pop #=> 6
35
+ #
36
+ # Thus, smaller elements will be parent nodes. The heap defaults to a min-heap if no block
37
+ # is given.
38
+ def initialize(ary=[], &block)
39
+ @compare_fn = block || lambda { |x, y| (x <=> y) == -1 }
40
+ @next = nil
41
+ @size = 0
42
+ @stored = {}
43
+
44
+ ary.each { |n| push(n) } unless ary.empty?
45
+ end
46
+
47
+ # call-seq:
48
+ # push(key, value) -> value
49
+ # push(value) -> value
50
+ #
51
+ # Inserts an item with a given key into the heap. If only one parameter is given,
52
+ # the key is set to the value.
53
+ #
54
+ # Complexity: O(1)
55
+ #
56
+ # heap = MinHeap.new
57
+ # heap.push(1, "Cat")
58
+ # heap.push(2)
59
+ # heap.pop #=> "Cat"
60
+ # heap.pop #=> 2
61
+ def push(key, value=key)
62
+ raise ArgumentError, "Heap keys must not be nil." unless key
63
+ node = Node.new(key, value)
64
+ # Add new node to the left of the @next node
65
+ if @next
66
+ node.right = @next
67
+ node.left = @next.left
68
+ node.left.right = node
69
+ @next.left = node
70
+ if @compare_fn[key, @next.key]
71
+ @next = node
72
+ end
73
+ else
74
+ @next = node
75
+ end
76
+ @size += 1
77
+
78
+ arr = []
79
+ w = @next.right
80
+ until w == @next do
81
+ arr << w.value
82
+ w = w.right
83
+ end
84
+ arr << @next.value
85
+ @stored[key] ||= []
86
+ @stored[key] << node
87
+ value
88
+ end
89
+ alias_method :<<, :push
90
+
91
+ # call-seq:
92
+ # has_key?(key) -> true or false
93
+ #
94
+ # Returns true if heap contains the key.
95
+ #
96
+ # Complexity: O(1)
97
+ #
98
+ # minheap = MinHeap.new([1, 2])
99
+ # minheap.has_key?(2) #=> true
100
+ # minheap.has_key?(4) #=> false
101
+ def has_key?(key)
102
+ @stored[key] && !@stored[key].empty? ? true : false
103
+ end
104
+
105
+ # call-seq:
106
+ # next -> value
107
+ # next -> nil
108
+ #
109
+ # Returns the value of the next item in heap order, but does not remove it.
110
+ #
111
+ # Complexity: O(1)
112
+ #
113
+ # minheap = MinHeap.new([1, 2])
114
+ # minheap.next #=> 1
115
+ # minheap.size #=> 2
116
+ def next
117
+ @next && @next.value
118
+ end
119
+
120
+ # call-seq:
121
+ # next_key -> key
122
+ # next_key -> nil
123
+ #
124
+ # Returns the key associated with the next item in heap order, but does not remove the value.
125
+ #
126
+ # Complexity: O(1)
127
+ #
128
+ # minheap = MinHeap.new
129
+ # minheap.push(1, :a)
130
+ # minheap.next_key #=> 1
131
+ #
132
+ def next_key
133
+ @next && @next.key
134
+ end
135
+
136
+ # call-seq:
137
+ # clear -> nil
138
+ #
139
+ # Removes all elements from the heap, destructively.
140
+ #
141
+ # Complexity: O(1)
142
+ #
143
+ def clear
144
+ @next = nil
145
+ @size = 0
146
+ @stored = {}
147
+ nil
148
+ end
149
+
150
+ # call-seq:
151
+ # empty? -> true or false
152
+ #
153
+ # Returns true if the heap is empty, false otherwise.
154
+ def empty?
155
+ @next.nil?
156
+ end
157
+
158
+ # call-seq:
159
+ # merge!(otherheap) -> merged_heap
160
+ #
161
+ # Does a shallow merge of all the nodes in the other heap.
162
+ #
163
+ # Complexity: O(1)
164
+ #
165
+ # heap = MinHeap.new([5, 6, 7, 8])
166
+ # otherheap = MinHeap.new([1, 2, 3, 4])
167
+ # heap.merge!(otherheap)
168
+ # heap.size #=> 8
169
+ # heap.pop #=> 1
170
+ def merge!(otherheap)
171
+ raise ArgumentError, "Trying to merge a heap with something not a heap" unless otherheap.kind_of? Containers::Heap
172
+ other_root = otherheap.instance_variable_get("@next")
173
+ if other_root
174
+ @stored = @stored.merge(otherheap.instance_variable_get("@stored")) { |key, a, b| (a << b).flatten }
175
+ # Insert othernode's @next node to the left of current @next
176
+ @next.left.right = other_root
177
+ ol = other_root.left
178
+ other_root.left = @next.left
179
+ ol.right = @next
180
+ @next.left = ol
181
+
182
+ @next = other_root if @compare_fn[other_root.key, @next.key]
183
+ end
184
+ @size += otherheap.size
185
+ end
186
+
187
+ # call-seq:
188
+ # pop -> value
189
+ # pop -> nil
190
+ #
191
+ # Returns the value of the next item in heap order and removes it from the heap.
192
+ #
193
+ # Complexity: O(1)
194
+ #
195
+ # minheap = MinHeap.new([1, 2])
196
+ # minheap.pop #=> 1
197
+ # minheap.size #=> 1
198
+ def pop
199
+ return nil unless @next
200
+ popped = @next
201
+ if @size == 1
202
+ clear
203
+ return popped.value
204
+ end
205
+ # Merge the popped's children into root node
206
+ if @next.child
207
+ @next.child.parent = nil
208
+
209
+ # get rid of parent
210
+ sibling = @next.child.right
211
+ until sibling == @next.child
212
+ sibling.parent = nil
213
+ sibling = sibling.right
214
+ end
215
+
216
+ # Merge the children into the root. If @next is the only root node, make its child the @next node
217
+ if @next.right == @next
218
+ @next = @next.child
219
+ else
220
+ next_left, next_right = @next.left, @next.right
221
+ current_child = @next.child
222
+ @next.right.left = current_child
223
+ @next.left.right = current_child.right
224
+ current_child.right.left = next_left
225
+ current_child.right = next_right
226
+ @next = @next.right
227
+ end
228
+ else
229
+ @next.left.right = @next.right
230
+ @next.right.left = @next.left
231
+ @next = @next.right
232
+ end
233
+ consolidate
234
+
235
+ unless @stored[popped.key].delete(popped)
236
+ raise "Couldn't delete node from stored nodes hash"
237
+ end
238
+ @size -= 1
239
+
240
+ popped.value
241
+ end
242
+ alias_method :next!, :pop
243
+
244
+ # call-seq:
245
+ # change_key(key, new_key) -> [new_key, value]
246
+ # change_key(key, new_key) -> nil
247
+ #
248
+ # Changes the key from one to another. Doing so must not violate the heap property or
249
+ # an exception will be raised. If the key is found, an array containing the new key and
250
+ # value pair is returned, otherwise nil is returned.
251
+ #
252
+ # In the case of duplicate keys, an arbitrary key is changed. This will be investigated
253
+ # more in the future.
254
+ #
255
+ # Complexity: amortized O(1)
256
+ #
257
+ # minheap = MinHeap.new([1, 2])
258
+ # minheap.change_key(2, 3) #=> raise error since we can't increase the value in a min-heap
259
+ # minheap.change_key(2, 0) #=> [0, 2]
260
+ # minheap.pop #=> 2
261
+ # minheap.pop #=> 1
262
+ def change_key(key, new_key, delete=false)
263
+ return if @stored[key].nil? || @stored[key].empty? || (key == new_key)
264
+
265
+ # Must maintain heap property
266
+ raise "Changing this key would not maintain heap property!" unless (delete || @compare_fn[new_key, key])
267
+ node = @stored[key].shift
268
+ if node
269
+ node.key = new_key
270
+ @stored[new_key] ||= []
271
+ @stored[new_key] << node
272
+ parent = node.parent
273
+ if parent
274
+ # if heap property is violated
275
+ if delete || @compare_fn[new_key, parent.key]
276
+ cut(node, parent)
277
+ cascading_cut(parent)
278
+ end
279
+ end
280
+ if delete || @compare_fn[node.key, @next.key]
281
+ @next = node
282
+ end
283
+ return [node.key, node.value]
284
+ end
285
+ nil
286
+ end
287
+
288
+ # call-seq:
289
+ # delete(key) -> value
290
+ # delete(key) -> nil
291
+ #
292
+ # Deletes the item with associated key and returns it. nil is returned if the key
293
+ # is not found. In the case of nodes with duplicate keys, an arbitrary one is deleted.
294
+ #
295
+ # Complexity: amortized O(log n)
296
+ #
297
+ # minheap = MinHeap.new([1, 2])
298
+ # minheap.delete(1) #=> 1
299
+ # minheap.size #=> 1
300
+ def delete(key)
301
+ pop if change_key(key, nil, true)
302
+ end
303
+
304
+ # Node class used internally
305
+ class Node # :nodoc:
306
+ attr_accessor :parent, :child, :left, :right, :key, :value, :degree, :marked
307
+
308
+ def initialize(key, value)
309
+ @key = key
310
+ @value = value
311
+ @degree = 0
312
+ @marked = false
313
+ @right = self
314
+ @left = self
315
+ end
316
+
317
+ def marked?
318
+ @marked == true
319
+ end
320
+
321
+ end
322
+
323
+ # make node a child of a parent node
324
+ def link_nodes(child, parent)
325
+ # link the child's siblings
326
+ child.left.right = child.right
327
+ child.right.left = child.left
328
+
329
+ child.parent = parent
330
+
331
+ # if parent doesn't have children, make new child its only child
332
+ if parent.child.nil?
333
+ parent.child = child.right = child.left = child
334
+ else # otherwise insert new child into parent's children list
335
+ current_child = parent.child
336
+ child.left = current_child
337
+ child.right = current_child.right
338
+ current_child.right.left = child
339
+ current_child.right = child
340
+ end
341
+ parent.degree += 1
342
+ child.marked = false
343
+ end
344
+ private :link_nodes
345
+
346
+ # Makes sure the structure does not contain nodes in the root list with equal degrees
347
+ def consolidate
348
+ roots = []
349
+ root = @next
350
+ min = root
351
+ # find the nodes in the list
352
+ loop do
353
+ roots << root
354
+ root = root.right
355
+ break if root == @next
356
+ end
357
+ degrees = []
358
+ roots.each do |root|
359
+ min = root if @compare_fn[root.key, min.key]
360
+ # check if we need to merge
361
+ if degrees[root.degree].nil? # no other node with the same degree
362
+ degrees[root.degree] = root
363
+ next
364
+ else # there is another node with the same degree, consolidate them
365
+ degree = root.degree
366
+ until degrees[degree].nil? do
367
+ other_root_with_degree = degrees[degree]
368
+ if @compare_fn[root.key, other_root_with_degree.key] # determine which node is the parent, which one is the child
369
+ smaller, larger = root, other_root_with_degree
370
+ else
371
+ smaller, larger = other_root_with_degree, root
372
+ end
373
+ link_nodes(larger, smaller)
374
+ degrees[degree] = nil
375
+ root = smaller
376
+ degree += 1
377
+ end
378
+ degrees[degree] = root
379
+ min = root if min.key == root.key # this fixes a bug with duplicate keys not being in the right order
380
+ end
381
+ end
382
+ @next = min
383
+ end
384
+ private :consolidate
385
+
386
+ def cascading_cut(node)
387
+ p = node.parent
388
+ if p
389
+ if node.marked?
390
+ cut(node, p)
391
+ cascading_cut(p)
392
+ else
393
+ node.marked = true
394
+ end
395
+ end
396
+ end
397
+ private :cascading_cut
398
+
399
+ # remove x from y's children and add x to the root list
400
+ def cut(x, y)
401
+ x.left.right = x.right
402
+ x.right.left = x.left
403
+ y.degree -= 1
404
+ if (y.degree == 0)
405
+ y.child = nil
406
+ elsif (y.child == x)
407
+ y.child = x.right
408
+ end
409
+ x.right = @next
410
+ x.left = @next.left
411
+ @next.left = x
412
+ x.left.right = x
413
+ x.parent = nil
414
+ x.marked = false
415
+ end
416
+ private :cut
417
+
418
+ end
419
+
420
+ # A MaxHeap is a heap where the items are returned in descending order of key value.
421
+ class Containers::MaxHeap < Containers::Heap
422
+
423
+ # call-seq:
424
+ # MaxHeap.new(ary) -> new_heap
425
+ #
426
+ # Creates a new MaxHeap with an optional array parameter of items to insert into the heap.
427
+ # A MaxHeap is created by calling Heap.new { |x, y| (x <=> y) == 1 }, so this is a convenience class.
428
+ #
429
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
430
+ # maxheap.pop #=> 4
431
+ # maxheap.pop #=> 3
432
+ def initialize(ary=[])
433
+ super(ary) { |x, y| (x <=> y) == 1 }
434
+ end
435
+
436
+ # call-seq:
437
+ # max -> value
438
+ # max -> nil
439
+ #
440
+ # Returns the item with the largest key, but does not remove it from the heap.
441
+ #
442
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
443
+ # maxheap.max #=> 4
444
+ def max
445
+ self.next
446
+ end
447
+
448
+ # call-seq:
449
+ # max! -> value
450
+ # max! -> nil
451
+ #
452
+ # Returns the item with the largest key and removes it from the heap.
453
+ #
454
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
455
+ # maxheap.max! #=> 4
456
+ # maxheap.size #=> 3
457
+ def max!
458
+ self.pop
459
+ end
460
+ end
461
+
462
+ # A MinHeap is a heap where the items are returned in ascending order of key value.
463
+ class Containers::MinHeap < Containers::Heap
464
+
465
+ # call-seq:
466
+ # MinHeap.new(ary) -> new_heap
467
+ #
468
+ # Creates a new MinHeap with an optional array parameter of items to insert into the heap.
469
+ # A MinHeap is created by calling Heap.new { |x, y| (x <=> y) == -1 }, so this is a convenience class.
470
+ #
471
+ # minheap = MinHeap.new([1, 2, 3, 4])
472
+ # minheap.pop #=> 1
473
+ # minheap.pop #=> 2
474
+ def initialize(ary=[])
475
+ super(ary) { |x, y| (x <=> y) == -1 }
476
+ end
477
+
478
+ # call-seq:
479
+ # min -> value
480
+ # min -> nil
481
+ #
482
+ # Returns the item with the smallest key, but does not remove it from the heap.
483
+ #
484
+ # minheap = MinHeap.new([1, 2, 3, 4])
485
+ # minheap.min #=> 1
486
+ def min
487
+ self.next
488
+ end
489
+
490
+ # call-seq:
491
+ # min! -> value
492
+ # min! -> nil
493
+ #
494
+ # Returns the item with the smallest key and removes it from the heap.
495
+ #
496
+ # minheap = MinHeap.new([1, 2, 3, 4])
497
+ # minheap.min! #=> 1
498
+ # minheap.size #=> 3
499
+ def min!
500
+ self.pop
501
+ end
507
502
  end