fibonacci_heap 0.1.0 → 0.2.0

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
  SHA256:
3
- metadata.gz: 9d5517c8d52edce5c8e372cd14457efe425f6a422fec8a02585221df8fa2f25a
4
- data.tar.gz: 3a6e50318184cfa233fe840e91806a209379dccc5dde84f7739b8921e3d73712
3
+ metadata.gz: 68aaf5872d76003db0e72b8e732fb657cf02da219739fb152739bc943cd19ef5
4
+ data.tar.gz: 9ac530f4499a41aca100ad0b7f22f802f161f8b5c51b0f5137cc181301a9b19a
5
5
  SHA512:
6
- metadata.gz: 6a93299721795318e9cd8529e899d710a32fb2bfde25b825d31a37a1318e78afa62bece5d26d4010a3a1cfa8c6a6420c5754c47e14cc56f02f1a40545911c37a
7
- data.tar.gz: 4790e9bbf353167b8a018e9e2a6b463a4159b5e5b0d434895e850466c495f55df7e92fc4744c2c25120c6474d4219382b428f905f82e56051d053db59710bd74
6
+ metadata.gz: 1bd78f32dabd4ac5763f2c6452c4be430e077cbf0f10290a7792cf97599439d7eeb369c6aed42cc3e473657025583b4eb98f868ad45cc6a76aa444a2f6228d32
7
+ data.tar.gz: 0532212274f8f18902664c608b0bf3fe2a933eec70e84249b5f0f891795ccafb3dcb0ccdccdbd75dba6e412cc1146d82476999a09b9bf32d7d22f5dbecb70d5e
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A Ruby implementation of the [Fibonacci heap](https://en.wikipedia.org/wiki/Fibonacci_heap) data structure ideal for use as a priority queue with [Dijkstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra's_algorithm#Using_a_priority_queue).
4
4
 
5
- **Current version:** 0.1.0
5
+ **Current version:** 0.2.0
6
6
  **Supported Ruby versions:** 1.8.7, 1.9.2, 1.9.3, 2.0, 2.1, 2.2, 2.3
7
7
 
8
8
  ## Installation
@@ -45,6 +45,7 @@ heap.pop
45
45
  * [`#pop`](#fibonacciheapheappop)
46
46
  * [`#decrease_key(x, k)`](#fibonacciheapheapdecrease_keyx-k)
47
47
  * [`#delete(x)`](#fibonacciheapheapdeletex)
48
+ * [`#clear`](#fibonacciheapheapclear)
48
49
  * [`FibonacciHeap::Node`](#fibonacciheapnode)
49
50
  * [`new(key[, value])`](#fibonacciheapnodenewkey-value)
50
51
  * [`key`](#fibonacciheapnodekey)
@@ -66,7 +67,7 @@ heap = FibonacciHeap::Heap.new
66
67
  #=> #<FibonacciHeap n=0 min=nil>
67
68
  ```
68
69
 
69
- Return a new, empty `FibonacciHeap::Heap` instance.
70
+ Return a new, empty [`FibonacciHeap::Heap`](#fibonacciheapheap) instance.
70
71
 
71
72
  #### `FibonacciHeap::Heap#n`
72
73
 
@@ -105,7 +106,7 @@ heap.min
105
106
  #=> #<FibonacciHeap::Node key=1 ...>
106
107
  ```
107
108
 
108
- Return the smallest `FibonacciHeap::Node` node in the heap as determined by the node's `key`.
109
+ Return the smallest [`FibonacciHeap::Node`](#fibonacciheapnode) node in the heap as determined by the node's `key`.
109
110
 
110
111
  Will return `nil` if the heap is empty.
111
112
 
@@ -119,7 +120,7 @@ heap.insert(node)
119
120
  heap.insert(bar, 100)
120
121
  ```
121
122
 
122
- Insert the given `FibonacciHeap::Node` `x` into the heap with an optional key `k`.
123
+ Insert the given [`FibonacciHeap::Node`](#fibonacciheapnode) `x` into the heap with an optional key `k`.
123
124
 
124
125
  Defaults to using `x`'s existing `key` for `k`.
125
126
 
@@ -140,7 +141,7 @@ heap3.pop
140
141
  #=> #<FibonacciHeap::Node key=2 value="bar" ...>
141
142
  ```
142
143
 
143
- Unite the given `FibonacciHeap::Heap` `h2` with this one in a new `FibonacciHeap::Heap`.
144
+ Unite the given [`FibonacciHeap::Heap`](#fibonacciheapheap) `h2` with this one in a new [`FibonacciHeap::Heap`](#fibonacciheapheap).
144
145
 
145
146
  As this will mutate both collections of rooted trees, attempting to use either the original heap or `h2` after `concat` has undefined behaviour.
146
147
 
@@ -153,7 +154,7 @@ heap.pop
153
154
  #=> #<FibonacciHeap::Node key=1 value="foo" ...>
154
155
  ```
155
156
 
156
- Remove and return the smallest `FibonacciHeap::Node` from the heap.
157
+ Remove and return the smallest [`FibonacciHeap::Node`](#fibonacciheapnode) from the heap.
157
158
 
158
159
  #### `FibonacciHeap::Heap#decrease_key(x, k)`
159
160
 
@@ -165,11 +166,11 @@ heap.decrease_key(node, 0)
165
166
  #=> #<FibonacciHeap::Node key=0 value="foo">
166
167
  ```
167
168
 
168
- Decrease the key of the given `FibonacciHeap::Node` `x` to the new given key `k`.
169
+ Decrease the key of the given [`FibonacciHeap::Node`](#fibonacciheapnode) `x` to the new given key `k`.
169
170
 
170
171
  The node must already be inserted into the heap and the key must be comparable.
171
172
 
172
- Raises a `FibonacciHeap::InvalidKeyError` if the new key is greater than the current key.
173
+ Raises a [`FibonacciHeap::InvalidKeyError`](#fibonacciheapinvalidkeyerror) if the new key is greater than the current key.
173
174
 
174
175
  #### `FibonacciHeap::Heap#delete(x)`
175
176
 
@@ -181,13 +182,24 @@ heap.delete(node)
181
182
  #=> #<FibonacciHeap::Node key=-Infinity value="foo">
182
183
  ```
183
184
 
184
- Deletes the given `FibonacciHeap::Node` `x` from the heap.
185
+ Deletes the given [`FibonacciHeap::Node`](#fibonacciheapnode) `x` from the heap.
185
186
 
186
187
  The node must already be inserted into the heap.
187
188
 
189
+ #### `FibonacciHeap::Heap#clear`
190
+
191
+ ```ruby
192
+ heap = FibonacciHeap::Heap.new
193
+ heap.insert(FibonacciHeap::Node.new(1, 'foo'))
194
+ heap.clear
195
+ #=> #<FibonacciHeap::Heap n=0 min=nil>
196
+ ```
197
+
198
+ Remove all nodes from the heap, emptying it.
199
+
188
200
  ### `FibonacciHeap::Node`
189
201
 
190
- A single node in a `FibonacciHeap::Heap`.
202
+ A single node in a [`FibonacciHeap::Heap`](#fibonacciheapheap).
191
203
 
192
204
  Used internally to form both min-heap ordered trees and circular, doubly linked lists.
193
205
 
@@ -200,7 +212,7 @@ node = FibonacciHeap::Node.new(1, 'foo')
200
212
  #=> #<FibonacciHeap::Node key=1 value="foo">
201
213
  ```
202
214
 
203
- Return a new `FibonacciHeap::Node` with the given key `key` and an optional value `value`.
215
+ Return a new [`FibonacciHeap::Node`](#fibonacciheapnode) with the given key `key` and an optional value `value`.
204
216
 
205
217
  Defaults to using the `key` as the value.
206
218
 
@@ -226,7 +238,7 @@ Return the current value of the node.
226
238
 
227
239
  ### `FibonacciHeap::InvalidKeyError`
228
240
 
229
- Raised when attempting to decrease a key but the key is greater than the current key.
241
+ Raised when attempting to decrease a key but the new key is greater than the current key.
230
242
 
231
243
  ## References
232
244
 
@@ -66,7 +66,7 @@ module FibonacciHeap
66
66
  list.sentinel.prev.next = sentinel.next
67
67
  sentinel.next.prev = list.sentinel.prev
68
68
  sentinel.next = list.sentinel.next
69
- list.sentinel.prev = sentinel
69
+ list.sentinel.next.prev = sentinel
70
70
  end
71
71
 
72
72
  # Yield each element of this list.
@@ -26,6 +26,7 @@ module FibonacciHeap
26
26
  @min = nil
27
27
  end
28
28
 
29
+ # Return whether or not this heap is empty.
29
30
  def empty?
30
31
  n.zero?
31
32
  end
@@ -65,15 +66,16 @@ module FibonacciHeap
65
66
  # Unite the given Fibonacci heap into this one, returning a new heap.
66
67
  #
67
68
  # Note that uniting the heaps will mutate their root lists, destroying them
68
- # both so attempting to use them has undefined behaviour.
69
+ # both so attempting to use them after uniting has undefined behaviour.
69
70
  #
70
71
  # Corresponds to the Fib-Heap-Union(H1, H2) procedure.
71
72
  def concat(h2)
72
73
  h = self.class.new
73
74
  h.min = min
74
75
 
75
- h.root_list = root_list
76
- h.root_list.concat(h2.root_list)
76
+ h.root_list = CircularDoublyLinkedList.new
77
+ h.root_list.concat(root_list) unless empty?
78
+ h.root_list.concat(h2.root_list) unless h2.empty?
77
79
 
78
80
  h.min = h2.min if !min || (h2.min && h2.min.key < min.key)
79
81
 
@@ -90,34 +92,30 @@ module FibonacciHeap
90
92
  # Corresponds to the Fib-Heap-Extract-Min(H) procedure.
91
93
  def pop
92
94
  z = min
95
+ return unless z
93
96
 
94
- if z
95
- # For each child x of z
96
- z.child_list.each do |x|
97
-
98
- # Add x to the root list of H
99
- root_list.insert(x)
100
- x.p = nil
101
- end
102
-
103
- # Remove z from the root list of H
104
- root_list.delete(z)
97
+ # For each child x of z
98
+ z.child_list.each do |x|
99
+ # Add x to the root list of H
100
+ root_list.insert(x)
101
+ x.p = nil
102
+ end
105
103
 
106
- # Is z the only node on the root list?
107
- if z.right == z.left
108
- # Empty the heap
109
- self.min = nil
110
- self.root_list = CircularDoublyLinkedList.new
111
- else
112
- # Set min to another root
113
- self.min = root_list.head
104
+ # Remove z from the root list of H
105
+ root_list.delete(z)
114
106
 
115
- consolidate
116
- end
107
+ # Was z the only node on the root list?
108
+ if z.right == z.left
109
+ self.min = nil
110
+ else
111
+ # Set min to another root
112
+ self.min = root_list.head
117
113
 
118
- self.n -= 1
114
+ consolidate
119
115
  end
120
116
 
117
+ self.n -= 1
118
+
121
119
  z
122
120
  end
123
121
 
@@ -156,6 +154,15 @@ module FibonacciHeap
156
154
  pop
157
155
  end
158
156
 
157
+ # Remove all nodes from the heap, emptying it.
158
+ def clear
159
+ self.root_list = CircularDoublyLinkedList.new
160
+ self.min = nil
161
+ self.n = 0
162
+
163
+ self
164
+ end
165
+
159
166
  def inspect
160
167
  %(#<#{self.class} n=#{n} min=#{min.inspect}>)
161
168
  end
@@ -164,7 +171,9 @@ module FibonacciHeap
164
171
 
165
172
  # Corresponds to the Consolidate(H) procedure.
166
173
  def consolidate
167
- degrees = []
174
+ # let A[0..D(H.n)] be a new array
175
+ max_degree = (Math.log(n) / Math.log(2)).floor
176
+ degrees = Array.new(max_degree + 1)
168
177
 
169
178
  root_list.each do |w|
170
179
  x = w
@@ -186,8 +195,8 @@ module FibonacciHeap
186
195
  end
187
196
 
188
197
  # Empty the root list
189
- self.min = nil
190
198
  self.root_list = CircularDoublyLinkedList.new
199
+ self.min = nil
191
200
 
192
201
  # Reconstruct the root list from the array A
193
202
  degrees.each do |root|
@@ -207,6 +216,7 @@ module FibonacciHeap
207
216
  def link(y, x)
208
217
  # remove y from the root list of H
209
218
  root_list.delete(y)
219
+
210
220
  # make y a child of x, incrementing x.degree
211
221
  x.child_list.insert(y)
212
222
  x.degree += 1
@@ -1,5 +1,3 @@
1
- require 'fibonacci_heap/circular_doubly_linked_list'
2
-
3
1
  module FibonacciHeap
4
2
  # A single node in a Fibonacci Heap.
5
3
  #
@@ -239,7 +239,7 @@ module FibonacciHeap
239
239
  expect(list).to contain_exactly(node, node2, node3, node4)
240
240
  end
241
241
 
242
- it 'combines an empty list a non-empty one' do
242
+ it 'combines an empty list with a non-empty one' do
243
243
  list = described_class.new
244
244
  list2 = described_class.new
245
245
  node = Node.new('foo')
@@ -252,6 +252,18 @@ module FibonacciHeap
252
252
  expect(list).to contain_exactly(node, node2)
253
253
  end
254
254
 
255
+ it 'removes any reference to the other list sentinel' do
256
+ list = described_class.new
257
+ list2 = described_class.new
258
+ node = Node.new('foo')
259
+ list2.insert(node)
260
+
261
+ list.concat(list2)
262
+
263
+ expect(node.next).to eq(list.sentinel)
264
+ expect(node.prev).to eq(list.sentinel)
265
+ end
266
+
255
267
  it 'combines a non-empty list with an empty one' do
256
268
  list = described_class.new
257
269
  list2 = described_class.new
@@ -23,6 +23,42 @@ module FibonacciHeap
23
23
  end
24
24
  end
25
25
 
26
+ describe '#clear' do
27
+ it 'empties the heap' do
28
+ heap = described_class.new
29
+ heap.insert(Node.new(1, 'foo'))
30
+
31
+ heap.clear
32
+
33
+ expect(heap).to be_empty
34
+ end
35
+
36
+ it 'clears the min node' do
37
+ heap = described_class.new
38
+ heap.insert(Node.new(1, 'foo'))
39
+
40
+ heap.clear
41
+
42
+ expect(heap.min).to be_nil
43
+ end
44
+
45
+ it 'empties the root list' do
46
+ heap = described_class.new
47
+ heap.insert(Node.new(1, 'foo'))
48
+
49
+ heap.clear
50
+
51
+ expect(heap.root_list).to be_empty
52
+ end
53
+
54
+ it 'returns the emptied heap' do
55
+ heap = described_class.new
56
+ heap.insert(Node.new(1, 'foo'))
57
+
58
+ expect(heap.clear).to eq(heap)
59
+ end
60
+ end
61
+
26
62
  describe '#n' do
27
63
  it 'returns the size of the heap' do
28
64
  heap = described_class.new
@@ -224,6 +260,28 @@ module FibonacciHeap
224
260
  expect(root.left).not_to eq(root.right)
225
261
  expect(root2.left).not_to eq(root2.right)
226
262
  end
263
+
264
+ it 'removes the last node in the heap' do
265
+ heap = described_class.new
266
+ root = Node.new('foo')
267
+ heap.insert(root)
268
+
269
+ expect(heap.pop).to eq(root)
270
+ expect(heap.pop).to be_nil
271
+ expect(heap.min).to be_nil
272
+ end
273
+
274
+ it 'can have nodes inserted after being emptied' do
275
+ heap = described_class.new
276
+ root = Node.new('foo')
277
+ heap.insert(root)
278
+ heap.pop
279
+ root2 = Node.new('bar')
280
+ heap.insert(root2)
281
+
282
+ expect(heap.pop).to eq(root2)
283
+ expect(heap.pop).to be_nil
284
+ end
227
285
  end
228
286
 
229
287
  describe '#decrease_key' do
@@ -292,7 +350,7 @@ module FibonacciHeap
292
350
  end
293
351
 
294
352
  describe '#concat' do
295
- it 'unite the given heap with this one' do
353
+ it 'unites the given heap with this one' do
296
354
  heap = described_class.new
297
355
  node = Node.new(1)
298
356
  heap2 = described_class.new
@@ -306,6 +364,39 @@ module FibonacciHeap
306
364
  expect(heap3.pop).to eq(node2)
307
365
  expect(heap3.pop).to be_nil
308
366
  end
367
+
368
+ it 'unites an empty heap with a non-empty heap' do
369
+ heap = described_class.new
370
+ heap2 = described_class.new
371
+ node = Node.new(1)
372
+ heap2.insert(node)
373
+
374
+ heap3 = heap.concat(heap2)
375
+
376
+ expect(heap3.pop).to eq(node)
377
+ expect(heap3.pop).to be_nil
378
+ end
379
+
380
+ it 'unites a non-empty heap with an empty heap' do
381
+ heap = described_class.new
382
+ heap2 = described_class.new
383
+ node = Node.new(1)
384
+ heap.insert(node)
385
+
386
+ heap3 = heap.concat(heap2)
387
+
388
+ expect(heap3.pop).to eq(node)
389
+ expect(heap3.pop).to be_nil
390
+ end
391
+
392
+ it 'unites two empty heaps' do
393
+ heap = described_class.new
394
+ heap2 = described_class.new
395
+
396
+ heap3 = heap.concat(heap2)
397
+
398
+ expect(heap3.pop).to be_nil
399
+ end
309
400
  end
310
401
  end
311
402
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fibonacci_heap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Mucur
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-13 00:00:00.000000000 Z
11
+ date: 2018-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec