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 +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
|