fibonacci_heap 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/README.md +24 -12
- data/lib/fibonacci_heap/circular_doubly_linked_list.rb +1 -1
- data/lib/fibonacci_heap/heap.rb +37 -27
- data/lib/fibonacci_heap/node.rb +0 -2
- data/spec/fibonacci_heap/circular_doubly_linked_list_spec.rb +13 -1
- data/spec/fibonacci_heap/heap_spec.rb +92 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68aaf5872d76003db0e72b8e732fb657cf02da219739fb152739bc943cd19ef5
|
4
|
+
data.tar.gz: 9ac530f4499a41aca100ad0b7f22f802f161f8b5c51b0f5137cc181301a9b19a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
data/lib/fibonacci_heap/heap.rb
CHANGED
@@ -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 =
|
76
|
-
h.root_list.concat(
|
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
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
107
|
-
|
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
|
-
|
116
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/fibonacci_heap/node.rb
CHANGED
@@ -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 '
|
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.
|
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-
|
11
|
+
date: 2018-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|