stakach-algorithms 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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