pairing_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/Gemfile.lock +5 -5
- data/README.md +623 -103
- data/lib/pairing_heap/version.rb +1 -1
- data/lib/pairing_heap.rb +166 -44
- data/pairing_heap.gemspec +5 -4
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfbfbd0337f23ec71179ae039bd54331178fbe5317c7fdd53730f8e9b2152656
|
4
|
+
data.tar.gz: a8fa80b6831cf3bbf2b13bafd72d7f899748c1698ac1c1d6300a3378b49a9dcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87d4f15844b9772ae6a13c2f1ec4a259f16a5a3091eaf4148730d487cc77d602939e3409de4314de8e1457800b718d6cb5d9624c81a7977eceef1f46d29ee02b
|
7
|
+
data.tar.gz: a78e724d551ec09e7058ad3f7a50580cff5769d5b5269973dacd36e85486df9dfdfb21da0606c6738bd134f6d151cbfbc50a3ace2f246433badd2cb02fbe91a2
|
data/Gemfile.lock
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pairing_heap (0.
|
4
|
+
pairing_heap (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
minitest (5.
|
10
|
-
rake (13.0.
|
9
|
+
minitest (5.15.0)
|
10
|
+
rake (13.0.6)
|
11
11
|
|
12
12
|
PLATFORMS
|
13
|
-
x86_64-darwin-
|
13
|
+
x86_64-darwin-21
|
14
14
|
|
15
15
|
DEPENDENCIES
|
16
16
|
minitest (~> 5.0)
|
@@ -18,4 +18,4 @@ DEPENDENCIES
|
|
18
18
|
rake (~> 13.0)
|
19
19
|
|
20
20
|
BUNDLED WITH
|
21
|
-
2.
|
21
|
+
2.3.6
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
PairingHeap is a pure Ruby priority queue implementation using a pairing heap as the underlying data structure. While a pairing heap is asymptotically less efficient than the Fibonacci heap, it is usually faster in practice. This makes it a popular choice for Prim's MST or Dijkstra's algorithm implementations.
|
4
4
|
|
5
|
+
Also implementation without priority change support is provided(`SimplePairingHeap`), while the asymptotical complexity of the methods stay the same, bookkeeping of elements is not needed making the constant smaller.
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
Add this line to your application's Gemfile:
|
@@ -18,10 +20,24 @@ Or install it yourself as:
|
|
18
20
|
|
19
21
|
$ gem install pairing_heap
|
20
22
|
|
23
|
+
|
24
|
+
## Documentation
|
25
|
+
https://rubydoc.info/gems/pairing_heap
|
26
|
+
|
21
27
|
## Usage
|
22
28
|
```ruby
|
23
29
|
require 'pairing_heap'
|
24
30
|
|
31
|
+
# Simple PairingHeap
|
32
|
+
simple_heap = PairingHeap::SimplePairingHeap.new
|
33
|
+
simple_heap.push(:a, 1)
|
34
|
+
simple_heap.push(:b, 2)
|
35
|
+
simple_heap.push(:c, 3)
|
36
|
+
simple_heap.peek # => :a
|
37
|
+
simple_heap.peek_priority # => [:a, 1]
|
38
|
+
simple_heap.pop_priority # => [:a, 1]
|
39
|
+
simple_heap.pop # => :b
|
40
|
+
|
25
41
|
# Min priority queue
|
26
42
|
best_defenses = PairingHeap::MinPriorityQueue.new
|
27
43
|
best_defenses.push('Chelsea', 24)
|
@@ -72,30 +88,33 @@ This API is a drop-in replacement of [lazy_priority_queue](https://github.com/ma
|
|
72
88
|
* `change_priority` returns `self` instead of the first argument
|
73
89
|
* `enqueue` returns `self` instead of the first argument
|
74
90
|
* Queue classes are in the `PairingHeap` namespace, so `require 'pairing_heap` does not load `MinPriorityQueue` to the global scope
|
75
|
-
* `
|
91
|
+
* `top_condition` constructor argument is removed
|
76
92
|
|
77
93
|
## Time Complexity
|
78
|
-
| Operation
|
79
|
-
| ---------------
|
80
|
-
| enqueue
|
81
|
-
| peek
|
82
|
-
|
|
83
|
-
|
|
84
|
-
| delete | O(n) | O(log n) |
|
94
|
+
| Operation | Time complexity | Amortized time complexity |
|
95
|
+
| --------------- | --------------- | ------------------------- |
|
96
|
+
| enqueue | O(1) | O(1) |
|
97
|
+
| peek | O(1) | O(1) |
|
98
|
+
| dequeue | O(n) | O(log n) |
|
99
|
+
| * change_priority | O(1) | o(log n) |
|
100
|
+
| * delete | O(n) | O(log n) |
|
101
|
+
|
102
|
+
`*` Not available in `SimplePairingHeap`
|
85
103
|
|
86
104
|
## Benchmarks
|
87
|
-
I picked the
|
105
|
+
I picked the three fastest pure Ruby priority queue implementations I was aware of for the comparison:
|
88
106
|
|
89
107
|
* [lazy_priority_queue](https://github.com/matiasbattocchia/lazy_priority_queue) that uses a lazy binomial heap. This is probably the most popular option, used for example in [RGL](https://github.com/monora/rgl/)
|
90
108
|
* Pure Ruby implementation of Fibonacci Heap from [priority-queue](https://github.com/supertinou/priority-queue) ([link to source](https://github.com/supertinou/priority-queue/blob/master/lib/priority_queue/ruby_priority_queue.rb))
|
109
|
+
* [rb_heap](https://github.com/florian/rb_heap) that uses a binary heap. Note however that this implementation does not support change_priority operation.
|
91
110
|
|
92
|
-
All tests except for the third one were executed by [benchmark-ips](https://github.com/evanphx/benchmark-ips) with parameters `time =
|
111
|
+
All tests except for the third one were executed by [benchmark-ips](https://github.com/evanphx/benchmark-ips) with parameters `time = 60` and `warmup = 15`, on an `Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz`.
|
93
112
|
### Stress test without changing priority test(N = 1000) [source code](./test/performance.rb)
|
94
113
|
Original performance test from [lazy_priority_queue](https://github.com/matiasbattocchia/lazy_priority_queue)
|
95
114
|
> A stress test of 1,000,000 operations: starting with 1,000 pushes/0 pops, following 999 pushes/1 pop, and so on till 0 pushes/1000 pops.
|
96
115
|
<table>
|
97
116
|
<tr>
|
98
|
-
<th colspan="4">ruby 3.
|
117
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]</th>
|
99
118
|
</tr>
|
100
119
|
<tr>
|
101
120
|
<th>Library</th>
|
@@ -104,25 +123,37 @@ Original performance test from [lazy_priority_queue](https://github.com/matiasba
|
|
104
123
|
<th>Iterations per second</th>
|
105
124
|
</tr>
|
106
125
|
<tr>
|
107
|
-
<td>pairing_heap</td>
|
108
|
-
<td>
|
109
|
-
<td>60.
|
110
|
-
<td>0.
|
126
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
127
|
+
<td>18</td>
|
128
|
+
<td>60.232046</td>
|
129
|
+
<td>0.299</td>
|
130
|
+
</tr>
|
131
|
+
<tr>
|
132
|
+
<td>pairing_heap (PairingHeap)</td>
|
133
|
+
<td>15</td>
|
134
|
+
<td>63.978031</td>
|
135
|
+
<td>0.234(1.27x slower)</td>
|
111
136
|
</tr>
|
112
137
|
<tr>
|
113
138
|
<td>lazy_priority_queue</td>
|
114
|
-
<td>
|
115
|
-
<td>
|
116
|
-
<td>0.
|
139
|
+
<td>9</td>
|
140
|
+
<td>60.031283</td>
|
141
|
+
<td>0.150(1.99x slower)</td>
|
142
|
+
</tr>
|
143
|
+
<tr>
|
144
|
+
<td>rb_heap</td>
|
145
|
+
<td>9</td>
|
146
|
+
<td>60.497355</td>
|
147
|
+
<td>0.149(2.01x slower)</td>
|
117
148
|
</tr>
|
118
149
|
<tr>
|
119
150
|
<td>Fibonacci</td>
|
120
151
|
<td>8</td>
|
121
|
-
<td>
|
122
|
-
<td>0.
|
152
|
+
<td>66.866055</td>
|
153
|
+
<td>0.120(2.50x slower)</td>
|
123
154
|
</tr>
|
124
155
|
<tr>
|
125
|
-
<th colspan="4">
|
156
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) +YJIT [x86_64-darwin21]</th>
|
126
157
|
</tr>
|
127
158
|
<tr>
|
128
159
|
<th>Library</th>
|
@@ -131,30 +162,120 @@ Original performance test from [lazy_priority_queue](https://github.com/matiasba
|
|
131
162
|
<th>Iterations per second</th>
|
132
163
|
</tr>
|
133
164
|
<tr>
|
134
|
-
<td>pairing_heap</td>
|
135
|
-
<td>
|
136
|
-
<td>
|
137
|
-
<td>0.
|
165
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
166
|
+
<td>22</td>
|
167
|
+
<td>62.866807</td>
|
168
|
+
<td>0.350</td>
|
169
|
+
</tr>
|
170
|
+
<tr>
|
171
|
+
<td>pairing_heap (PairingHeap)</td>
|
172
|
+
<td>16</td>
|
173
|
+
<td>61.358679</td>
|
174
|
+
<td>0.261(1.34x slower)</td>
|
175
|
+
</tr>
|
176
|
+
<tr>
|
177
|
+
<td>Fibonacci</td>
|
178
|
+
<td>14</td>
|
179
|
+
<td>64.394112</td>
|
180
|
+
<td>0.217(1.61x slower)</td>
|
181
|
+
</tr>
|
182
|
+
<tr>
|
183
|
+
<td>rb_heap</td>
|
184
|
+
<td>12</td>
|
185
|
+
<td>60.975479</td>
|
186
|
+
<td>0.197(1.78x slower)</td>
|
187
|
+
</tr>
|
188
|
+
<tr>
|
189
|
+
<td>lazy_priority_queue</td>
|
190
|
+
<td>11</td>
|
191
|
+
<td>65.568648</td>
|
192
|
+
<td>0.168(2.09x slower)</td>
|
193
|
+
</tr>
|
194
|
+
<tr>
|
195
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +jit [darwin-x86_64]</th>
|
196
|
+
</tr>
|
197
|
+
<tr>
|
198
|
+
<th>Library</th>
|
199
|
+
<th>Iterations</th>
|
200
|
+
<th>Seconds</th>
|
201
|
+
<th>Iterations per second</th>
|
202
|
+
</tr>
|
203
|
+
<tr>
|
204
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
205
|
+
<td>21</td>
|
206
|
+
<td>60.357577s</td>
|
207
|
+
<td>0.348</td>
|
208
|
+
</tr>
|
209
|
+
<tr>
|
210
|
+
<td>pairing_heap (PairingHeap)</td>
|
211
|
+
<td>15</td>
|
212
|
+
<td>60.417252</td>
|
213
|
+
<td>0.248(1.40x slower)</td>
|
138
214
|
</tr>
|
139
215
|
<tr>
|
140
216
|
<td>lazy_priority_queue</td>
|
141
217
|
<td>14</td>
|
142
|
-
<td>
|
143
|
-
<td>0.
|
218
|
+
<td>61.022450</td>
|
219
|
+
<td>0.229(1.52x slower)</td>
|
220
|
+
</tr>
|
221
|
+
<tr>
|
222
|
+
<td>rb_heap</td>
|
223
|
+
<td>13</td>
|
224
|
+
<td>63.661862</td>
|
225
|
+
<td>0.204(1.70x slower)</td>
|
144
226
|
</tr>
|
145
227
|
<tr>
|
146
228
|
<td>Fibonacci</td>
|
147
|
-
<td>
|
148
|
-
<td>
|
149
|
-
<td>0.
|
229
|
+
<td>8</td>
|
230
|
+
<td>62.643449</td>
|
231
|
+
<td>0.128(2.72x slower)</td>
|
232
|
+
</tr>
|
233
|
+
<tr>
|
234
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +indy +jit [darwin-x86_64]</th>
|
235
|
+
</tr>
|
236
|
+
<tr>
|
237
|
+
<th>Library</th>
|
238
|
+
<th>Iterations</th>
|
239
|
+
<th>Seconds</th>
|
240
|
+
<th>Iterations per second</th>
|
241
|
+
</tr>
|
242
|
+
<tr>
|
243
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
244
|
+
<td>43</td>
|
245
|
+
<td>60.472129</td>
|
246
|
+
<td>0.711</td>
|
247
|
+
</tr>
|
248
|
+
<tr>
|
249
|
+
<td>pairing_heap (PairingHeap)</td>
|
250
|
+
<td>30</td>
|
251
|
+
<td>60.359748</td>
|
252
|
+
<td>0.497(1.43x slower)</td>
|
253
|
+
</tr>
|
254
|
+
<tr>
|
255
|
+
<td>Fibonacci</td>
|
256
|
+
<td>25</td>
|
257
|
+
<td>62.084250</td>
|
258
|
+
<td>0.403(1.77x slower)</td>
|
259
|
+
</tr>
|
260
|
+
<tr>
|
261
|
+
<td>rb_heap</td>
|
262
|
+
<td>23</td>
|
263
|
+
<td>62.419893</td>
|
264
|
+
<td>0.369(1.93x slower)</td>
|
265
|
+
</tr>
|
266
|
+
<tr>
|
267
|
+
<td>lazy_priority_queue</td>
|
268
|
+
<td>22</td>
|
269
|
+
<td>60.947299</td>
|
270
|
+
<td>0.361(1.97x slower)</td>
|
150
271
|
</tr>
|
151
272
|
</table>
|
152
273
|
|
153
274
|
### Stress test with changing priority(N = 1000) [source code](./test/performance_with_change_priority.rb)
|
154
|
-
A stress test of
|
275
|
+
A stress test of 1,501,500 operations: starting with 1,000 pushes/1000 change_priorities/0 pops, following 999 pushes/999 change_priorities/1 pop, and so on till 0 pushes/0 change_priorities/1000 pops.
|
155
276
|
<table>
|
156
277
|
<tr>
|
157
|
-
<th colspan="4">ruby 3.
|
278
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]</th>
|
158
279
|
</tr>
|
159
280
|
<tr>
|
160
281
|
<th>Library</th>
|
@@ -164,24 +285,51 @@ A stress test of 2,000,000 operations: starting with 1,000 pushes/1000 change_pr
|
|
164
285
|
</tr>
|
165
286
|
<tr>
|
166
287
|
<td>pairing_heap</td>
|
167
|
-
<td>
|
168
|
-
<td>
|
169
|
-
<td>0.
|
288
|
+
<td>14</td>
|
289
|
+
<td>63.536300</td>
|
290
|
+
<td>0.220</td>
|
170
291
|
</tr>
|
171
292
|
<tr>
|
172
293
|
<td>lazy_priority_queue</td>
|
294
|
+
<td>9</td>
|
295
|
+
<td>63.319474s</td>
|
296
|
+
<td>0.142(1.55x slower)</td>
|
297
|
+
</tr>
|
298
|
+
<tr>
|
299
|
+
<td>Fibonacci</td>
|
173
300
|
<td>8</td>
|
174
|
-
<td>67.
|
175
|
-
<td>0.119(1.
|
301
|
+
<td>67.385714</td>
|
302
|
+
<td>0.119(1.86x slower)</td>
|
303
|
+
</tr>
|
304
|
+
<tr>
|
305
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) +YJIT [x86_64-darwin21]</th>
|
306
|
+
</tr>
|
307
|
+
<tr>
|
308
|
+
<th>Library</th>
|
309
|
+
<th>Iterations</th>
|
310
|
+
<th>Seconds</th>
|
311
|
+
<th>Iterations per second</th>
|
312
|
+
</tr>
|
313
|
+
<tr>
|
314
|
+
<td>pairing_heap</td>
|
315
|
+
<td>15</td>
|
316
|
+
<td>62.243080</td>
|
317
|
+
<td>0.241</td>
|
176
318
|
</tr>
|
177
319
|
<tr>
|
178
320
|
<td>Fibonacci</td>
|
179
|
-
<td>
|
180
|
-
<td>
|
181
|
-
<td>0.
|
321
|
+
<td>13</td>
|
322
|
+
<td>63.030390</td>
|
323
|
+
<td>0.206(1.17x slower)</td>
|
324
|
+
</tr>
|
325
|
+
<tr>
|
326
|
+
<td>lazy_priority_queue</td>
|
327
|
+
<td>10</td>
|
328
|
+
<td>64.865853</td>
|
329
|
+
<td>0.154(1.56x slower)</td>
|
182
330
|
</tr>
|
183
331
|
<tr>
|
184
|
-
<th colspan="4">jruby 9.
|
332
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +jit [darwin-x86_64]</th>
|
185
333
|
</tr>
|
186
334
|
<tr>
|
187
335
|
<th>Library</th>
|
@@ -191,29 +339,75 @@ A stress test of 2,000,000 operations: starting with 1,000 pushes/1000 change_pr
|
|
191
339
|
</tr>
|
192
340
|
<tr>
|
193
341
|
<td>pairing_heap</td>
|
194
|
-
<td>
|
195
|
-
<td>
|
196
|
-
<td>0.
|
342
|
+
<td>15</td>
|
343
|
+
<td>61.540851</td>
|
344
|
+
<td>0.244</td>
|
197
345
|
</tr>
|
198
346
|
<tr>
|
199
347
|
<td>lazy_priority_queue</td>
|
200
|
-
<td>
|
201
|
-
<td>
|
202
|
-
<td>0.
|
348
|
+
<td>14</td>
|
349
|
+
<td>61.471507</td>
|
350
|
+
<td>0.228(1.07x slower)</td>
|
203
351
|
</tr>
|
204
352
|
<tr>
|
205
353
|
<td>Fibonacci</td>
|
206
|
-
<td>
|
207
|
-
<td>
|
208
|
-
<td>0.
|
354
|
+
<td>9</td>
|
355
|
+
<td>67.393730</td>
|
356
|
+
<td>0.134(1.83x slower)</td>
|
357
|
+
</tr>
|
358
|
+
<tr>
|
359
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +indy +jit [darwin-x86_64]</th>
|
360
|
+
</tr>
|
361
|
+
<tr>
|
362
|
+
<th>Library</th>
|
363
|
+
<th>Iterations</th>
|
364
|
+
<th>Seconds</th>
|
365
|
+
<th>Iterations per second</th>
|
366
|
+
</tr>
|
367
|
+
<tr>
|
368
|
+
<td>pairing_heap</td>
|
369
|
+
<td>27</td>
|
370
|
+
<td>61.322001</td>
|
371
|
+
<td>0.440</td>
|
372
|
+
</tr>
|
373
|
+
<tr>
|
374
|
+
<td>Fibonacci</td>
|
375
|
+
<td>21</td>
|
376
|
+
<td>60.334636</td>
|
377
|
+
<td>0.349(1.26x slower)</td>
|
378
|
+
</tr>
|
379
|
+
<tr>
|
380
|
+
<td>lazy_priority_queue</td>
|
381
|
+
<td>20</td>
|
382
|
+
<td>61.471507</td>
|
383
|
+
<td>0.327(1.35x slower)</td>
|
209
384
|
</tr>
|
210
385
|
</table>
|
211
386
|
|
212
387
|
### Stress test with changing priority(N = 10) [source code](./test/performance_with_change_priority.rb)
|
213
|
-
A stress test of
|
388
|
+
A stress test of 165 operations: starting with 10 pushes/10 change_priorities/0 pops, following 9 pushes/9 change_priorities/1 pop, and so on till 0 pushes/0 change_priorities/10 pops.
|
214
389
|
<table>
|
215
390
|
<tr>
|
216
|
-
<th colspan="4">ruby 3.
|
391
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]</th>
|
392
|
+
</tr>
|
393
|
+
<tr>
|
394
|
+
<th>Library</th>
|
395
|
+
<th>Iterations per second</th>
|
396
|
+
</tr>
|
397
|
+
<tr>
|
398
|
+
<td>pairing_heap</td>
|
399
|
+
<td>5914.3</td>
|
400
|
+
</tr>
|
401
|
+
<tr>
|
402
|
+
<td>lazy_priority_queue</td>
|
403
|
+
<td>4293.5(1.38x slower)</td>
|
404
|
+
</tr>
|
405
|
+
<tr>
|
406
|
+
<td>Fibonacci</td>
|
407
|
+
<td>3755.2(1.57x slower)</td>
|
408
|
+
</tr>
|
409
|
+
<tr>
|
410
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) +YJIT [x86_64-darwin21]</th>
|
217
411
|
</tr>
|
218
412
|
<tr>
|
219
413
|
<th>Library</th>
|
@@ -221,18 +415,18 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
221
415
|
</tr>
|
222
416
|
<tr>
|
223
417
|
<td>pairing_heap</td>
|
224
|
-
<td>
|
418
|
+
<td>7082.7</td>
|
225
419
|
</tr>
|
226
420
|
<tr>
|
227
421
|
<td>Fibonacci</td>
|
228
|
-
<td>
|
422
|
+
<td>6687.1(1.06x slower)</td>
|
229
423
|
</tr>
|
230
424
|
<tr>
|
231
425
|
<td>lazy_priority_queue</td>
|
232
|
-
<td>
|
426
|
+
<td>5006.4(1.41x slower)</td>
|
233
427
|
</tr>
|
234
428
|
<tr>
|
235
|
-
<th colspan="4">jruby 9.
|
429
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +jit [darwin-x86_64]</th>
|
236
430
|
</tr>
|
237
431
|
<tr>
|
238
432
|
<th>Library</th>
|
@@ -240,22 +434,41 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
240
434
|
</tr>
|
241
435
|
<tr>
|
242
436
|
<td>pairing_heap</td>
|
243
|
-
<td>
|
437
|
+
<td>6861.6</td>
|
244
438
|
</tr>
|
245
439
|
<tr>
|
246
440
|
<td>lazy_priority_queue</td>
|
247
|
-
<td>
|
441
|
+
<td>6446.4(1.06x slower)</td>
|
248
442
|
</tr>
|
249
443
|
<tr>
|
250
444
|
<td>Fibonacci</td>
|
251
|
-
<td>
|
445
|
+
<td>4365.4(1.57x slower)</td>
|
446
|
+
</tr>
|
447
|
+
<tr>
|
448
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +indy +jit [darwin-x86_64]</th>
|
449
|
+
</tr>
|
450
|
+
<tr>
|
451
|
+
<th>Library</th>
|
452
|
+
<th>Iterations per second</th>
|
453
|
+
</tr>
|
454
|
+
<tr>
|
455
|
+
<td>pairing_heap</td>
|
456
|
+
<td>14032</td>
|
457
|
+
</tr>
|
458
|
+
<tr>
|
459
|
+
<td>Fibonacci</td>
|
460
|
+
<td>12841(1.09x slower)</td>
|
461
|
+
</tr>
|
462
|
+
<tr>
|
463
|
+
<td>lazy_priority_queue</td>
|
464
|
+
<td>10404(1.35x slower)</td>
|
252
465
|
</tr>
|
253
466
|
</table>
|
254
467
|
|
255
468
|
### Dijkstra's algorithm with RGL [source code](./test/performance_rgl.rb)
|
256
469
|
<table>
|
257
470
|
<tr>
|
258
|
-
<th colspan="4">ruby 3.
|
471
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]</th>
|
259
472
|
</tr>
|
260
473
|
<tr>
|
261
474
|
<th>Library</th>
|
@@ -265,24 +478,24 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
265
478
|
</tr>
|
266
479
|
<tr>
|
267
480
|
<td>pairing_heap</td>
|
268
|
-
<td>
|
269
|
-
<td>64.
|
270
|
-
<td>0.
|
481
|
+
<td>9</td>
|
482
|
+
<td>64.505899</td>
|
483
|
+
<td>0.140</td>
|
271
484
|
</tr>
|
272
485
|
<tr>
|
273
486
|
<td>lazy_priority_queue</td>
|
274
|
-
<td>
|
275
|
-
<td>63.
|
276
|
-
<td>0.
|
487
|
+
<td>8</td>
|
488
|
+
<td>63.970577</td>
|
489
|
+
<td>0.125(1.12x slower)</td>
|
277
490
|
</tr>
|
278
491
|
<tr>
|
279
492
|
<td>Fibonacci</td>
|
280
|
-
<td>
|
281
|
-
<td>
|
282
|
-
<td>0.
|
493
|
+
<td>7</td>
|
494
|
+
<td>62.573724</td>
|
495
|
+
<td>0.112(1.25x slower)</td>
|
283
496
|
</tr>
|
284
497
|
<tr>
|
285
|
-
<th colspan="4">
|
498
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) +YJIT [x86_64-darwin21]</th>
|
286
499
|
</tr>
|
287
500
|
<tr>
|
288
501
|
<th>Library</th>
|
@@ -292,28 +505,83 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
292
505
|
</tr>
|
293
506
|
<tr>
|
294
507
|
<td>pairing_heap</td>
|
295
|
-
<td>
|
296
|
-
<td>
|
297
|
-
<td>0.
|
508
|
+
<td>9</td>
|
509
|
+
<td>63.567801</td>
|
510
|
+
<td>0.142</td>
|
511
|
+
</tr>
|
512
|
+
<tr>
|
513
|
+
<td>Fibonacci</td>
|
514
|
+
<td>9</td>
|
515
|
+
<td>64.575079</td>
|
516
|
+
<td>0.140(1.02x slower)</td>
|
298
517
|
</tr>
|
299
518
|
<tr>
|
300
519
|
<td>lazy_priority_queue</td>
|
301
|
-
<td>
|
302
|
-
<td>
|
303
|
-
<td>0.
|
520
|
+
<td>8</td>
|
521
|
+
<td>60.123700</td>
|
522
|
+
<td>0.133(1.06x slower)</td>
|
523
|
+
</tr>
|
524
|
+
<tr>
|
525
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +jit [darwin-x86_64]</th>
|
526
|
+
</tr>
|
527
|
+
<tr>
|
528
|
+
<th>Library</th>
|
529
|
+
<th>Iterations</th>
|
530
|
+
<th>Seconds</th>
|
531
|
+
<th>Iterations per second</th>
|
532
|
+
</tr>
|
533
|
+
<tr>
|
534
|
+
<td>pairing_heap</td>
|
535
|
+
<td>14</td>
|
536
|
+
<td>64.124373</td>
|
537
|
+
<td>0.218</td>
|
538
|
+
</tr>
|
539
|
+
<tr>
|
540
|
+
<td>lazy_priority_queue</td>
|
541
|
+
<td>13</td>
|
542
|
+
<td>61.147807</td>
|
543
|
+
<td>0.213(1.03x slower)</td>
|
304
544
|
</tr>
|
305
545
|
<tr>
|
306
546
|
<td>Fibonacci</td>
|
307
547
|
<td>10</td>
|
308
|
-
<td>
|
309
|
-
<td>0.
|
548
|
+
<td>64.250067</td>
|
549
|
+
<td>0.156(1.40x slower)</td>
|
550
|
+
</tr>
|
551
|
+
<tr>
|
552
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +indy +jit [darwin-x86_64]</th>
|
553
|
+
</tr>
|
554
|
+
<tr>
|
555
|
+
<th>Library</th>
|
556
|
+
<th>Iterations</th>
|
557
|
+
<th>Seconds</th>
|
558
|
+
<th>Iterations per second</th>
|
559
|
+
</tr>
|
560
|
+
<tr>
|
561
|
+
<td>pairing_heap</td>
|
562
|
+
<td>22</td>
|
563
|
+
<td>61.450341</td>
|
564
|
+
<td>0.361</td>
|
565
|
+
</tr>
|
566
|
+
<tr>
|
567
|
+
<td>Fibonacci</td>
|
568
|
+
<td>18</td>
|
569
|
+
<td>61.618204</td>
|
570
|
+
<td>0.296(1.22x slower)</td>
|
571
|
+
</tr>
|
572
|
+
<tr>
|
573
|
+
<td>lazy_priority_queue</td>
|
574
|
+
<td>17</td>
|
575
|
+
<td>60.156184</td>
|
576
|
+
<td>0.283(1.27x slower)</td>
|
310
577
|
</tr>
|
311
578
|
</table>
|
312
579
|
|
313
580
|
### Simple Dijkstra's algorithm implementation [source code](./test/performance_dijkstra.rb)
|
581
|
+
Heaps that support change_priority operation use it. Heaps that do not support it use dijkstra implementation that do not rely on change_priority instead and do additional pops and pushes instead(see Dijkstra-NoDec from [Priority Queues and Dijkstra’s Algorithm](https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf)).
|
314
582
|
<table>
|
315
583
|
<tr>
|
316
|
-
<th colspan="4">ruby 3.
|
584
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]</th>
|
317
585
|
</tr>
|
318
586
|
<tr>
|
319
587
|
<th>Library</th>
|
@@ -322,25 +590,76 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
322
590
|
<th>Iterations per second</th>
|
323
591
|
</tr>
|
324
592
|
<tr>
|
325
|
-
<td>pairing_heap</td>
|
326
|
-
<td>
|
327
|
-
<td>
|
328
|
-
<td>0.
|
593
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
594
|
+
<td>25</td>
|
595
|
+
<td>61.386477</td>
|
596
|
+
<td>0.407</td>
|
597
|
+
</tr>
|
598
|
+
<tr>
|
599
|
+
<td>pairing_heap (PairingHeap)</td>
|
600
|
+
<td>22</td>
|
601
|
+
<td>62.044470</td>
|
602
|
+
<td>0.355(1.15x slower)</td>
|
603
|
+
</tr>
|
604
|
+
<tr>
|
605
|
+
<td>rb_heap</td>
|
606
|
+
<td>13</td>
|
607
|
+
<td>60.717112</td>
|
608
|
+
<td>0.214(1.90x slower)</td>
|
609
|
+
</tr>
|
610
|
+
<tr>
|
611
|
+
<td>lazy_priority_queue</td>
|
612
|
+
<td>10</td>
|
613
|
+
<td>61.730614</td>
|
614
|
+
<td>0.162(2.51x slower)</td>
|
329
615
|
</tr>
|
330
616
|
<tr>
|
331
617
|
<td>Fibonacci</td>
|
332
618
|
<td>10</td>
|
333
|
-
<td>
|
334
|
-
<td>0.
|
619
|
+
<td>65.899982</td>
|
620
|
+
<td>0.152(2.68x slower)</td>
|
621
|
+
</tr>
|
622
|
+
<tr>
|
623
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) +YJIT [x86_64-darwin21]</th>
|
624
|
+
</tr>
|
625
|
+
<tr>
|
626
|
+
<th>Library</th>
|
627
|
+
<th>Iterations</th>
|
628
|
+
<th>Seconds</th>
|
629
|
+
<th>Iterations per second</th>
|
630
|
+
</tr>
|
631
|
+
<tr>
|
632
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
633
|
+
<td>29</td>
|
634
|
+
<td>61.656995</td>
|
635
|
+
<td>0.471</td>
|
636
|
+
</tr>
|
637
|
+
<tr>
|
638
|
+
<td>pairing_heap (PairingHeap)</td>
|
639
|
+
<td>24</td>
|
640
|
+
<td>61.813482</td>
|
641
|
+
<td>0.389(1.21x slower)</td>
|
642
|
+
</tr>
|
643
|
+
<tr>
|
644
|
+
<td>rb_heap</td>
|
645
|
+
<td>19</td>
|
646
|
+
<td>62.191040</td>
|
647
|
+
<td>0.306(1.54x slower)</td>
|
648
|
+
</tr>
|
649
|
+
<tr>
|
650
|
+
<td>Fibonacci</td>
|
651
|
+
<td>18</td>
|
652
|
+
<td>60.062072</td>
|
653
|
+
<td>0.300(1.57x slower)</td>
|
335
654
|
</tr>
|
336
655
|
<tr>
|
337
656
|
<td>lazy_priority_queue</td>
|
338
|
-
<td>
|
339
|
-
<td>
|
340
|
-
<td>0.
|
657
|
+
<td>12</td>
|
658
|
+
<td>60.860292</td>
|
659
|
+
<td>0.197(2.38x slower)</td>
|
341
660
|
</tr>
|
342
661
|
<tr>
|
343
|
-
<th colspan="4">jruby 9.
|
662
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +jit [darwin-x86_64]</th>
|
344
663
|
</tr>
|
345
664
|
<tr>
|
346
665
|
<th>Library</th>
|
@@ -349,29 +668,100 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
349
668
|
<th>Iterations per second</th>
|
350
669
|
</tr>
|
351
670
|
<tr>
|
352
|
-
<td>pairing_heap</td>
|
353
|
-
<td>
|
354
|
-
<td>61.
|
355
|
-
<td>0.
|
671
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
672
|
+
<td>24</td>
|
673
|
+
<td>61.972936</td>
|
674
|
+
<td>0.387</td>
|
675
|
+
</tr>
|
676
|
+
<tr>
|
677
|
+
<td>pairing_heap (PairingHeap)</td>
|
678
|
+
<td>20</td>
|
679
|
+
<td>62.178839</td>
|
680
|
+
<td>0.322(1.20x slower)</td>
|
356
681
|
</tr>
|
357
682
|
<tr>
|
358
683
|
<td>lazy_priority_queue</td>
|
359
684
|
<td>14</td>
|
360
|
-
<td>
|
361
|
-
<td>0.
|
685
|
+
<td>61.540058s</td>
|
686
|
+
<td>0.228(1.70x slower)</td>
|
687
|
+
</tr>
|
688
|
+
<tr>
|
689
|
+
<td>rb_heap</td>
|
690
|
+
<td>14</td>
|
691
|
+
<td>62.125831</td>
|
692
|
+
<td>0.225(1.72x slower)</td>
|
362
693
|
</tr>
|
363
694
|
<tr>
|
364
695
|
<td>Fibonacci</td>
|
365
696
|
<td>10</td>
|
366
|
-
<td>62.
|
367
|
-
<td>0.
|
697
|
+
<td>62.319669</td>
|
698
|
+
<td>0.155(2.41x slower)</td>
|
699
|
+
</tr>
|
700
|
+
<tr>
|
701
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +indy +jit [darwin-x86_64]</th>
|
702
|
+
</tr>
|
703
|
+
<tr>
|
704
|
+
<th>Library</th>
|
705
|
+
<th>Iterations</th>
|
706
|
+
<th>Seconds</th>
|
707
|
+
<th>Iterations per second</th>
|
708
|
+
</tr>
|
709
|
+
<tr>
|
710
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
711
|
+
<td>47</td>
|
712
|
+
<td>61.192519</td>
|
713
|
+
<td>0.770</td>
|
714
|
+
</tr>
|
715
|
+
<tr>
|
716
|
+
<td>rb_heap</td>
|
717
|
+
<td>39</td>
|
718
|
+
<td>61.028398</td>
|
719
|
+
<td>0.639(1.20x slower)</td>
|
720
|
+
</tr>
|
721
|
+
<tr>
|
722
|
+
<td>pairing_heap (PairingHeap)</td>
|
723
|
+
<td>36</td>
|
724
|
+
<td>60.035760</td>
|
725
|
+
<td>0.601(1.28x slower)</td>
|
726
|
+
</tr>
|
727
|
+
<tr>
|
728
|
+
<td>Fibonacci</td>
|
729
|
+
<td>28</td>
|
730
|
+
<td>61.599202</td>
|
731
|
+
<td>0.456(1.69x slower)</td>
|
732
|
+
</tr>
|
733
|
+
<tr>
|
734
|
+
<td>lazy_priority_queue</td>
|
735
|
+
<td>22</td>
|
736
|
+
<td>60.540367</td>
|
737
|
+
<td>0.364(2.12x slower)</td>
|
368
738
|
</tr>
|
369
739
|
</table>
|
370
740
|
|
371
741
|
### Summary
|
742
|
+
#### Change priority required
|
372
743
|
<table>
|
373
744
|
<tr>
|
374
|
-
<th colspan="4">ruby 3.
|
745
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]</th>
|
746
|
+
</tr>
|
747
|
+
<tr>
|
748
|
+
<th>Library</th>
|
749
|
+
<th>Slower geometric mean</th>
|
750
|
+
</tr>
|
751
|
+
<tr>
|
752
|
+
<td>pairing_heap</td>
|
753
|
+
<td>1</td>
|
754
|
+
</tr>
|
755
|
+
<tr>
|
756
|
+
<td>lazy_priority_queue</td>
|
757
|
+
<td>1.523x slower</td>
|
758
|
+
</tr>
|
759
|
+
<tr>
|
760
|
+
<td>Fibonacci</td>
|
761
|
+
<td>1.751x slower</td>
|
762
|
+
</tr>
|
763
|
+
<tr>
|
764
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) +YJIT [x86_64-darwin21]</th>
|
375
765
|
</tr>
|
376
766
|
<tr>
|
377
767
|
<th>Library</th>
|
@@ -383,14 +773,14 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
383
773
|
</tr>
|
384
774
|
<tr>
|
385
775
|
<td>Fibonacci</td>
|
386
|
-
<td>1.
|
776
|
+
<td>1.146x slower</td>
|
387
777
|
</tr>
|
388
778
|
<tr>
|
389
779
|
<td>lazy_priority_queue</td>
|
390
|
-
<td>1.
|
780
|
+
<td>1.482x slower</td>
|
391
781
|
</tr>
|
392
782
|
<tr>
|
393
|
-
<th colspan="4">jruby 9.
|
783
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +jit [darwin-x86_64]</th>
|
394
784
|
</tr>
|
395
785
|
<tr>
|
396
786
|
<th>Library</th>
|
@@ -402,15 +792,145 @@ A stress test of 200 operations: starting with 10 pushes/10 change_priorities/0
|
|
402
792
|
</tr>
|
403
793
|
<tr>
|
404
794
|
<td>lazy_priority_queue</td>
|
405
|
-
<td>1.
|
795
|
+
<td>1.153x slower</td>
|
406
796
|
|
407
797
|
</tr>
|
408
798
|
<tr>
|
409
799
|
<td>Fibonacci</td>
|
410
|
-
<td>1.
|
800
|
+
<td>1.793x slower</td>
|
801
|
+
</tr>
|
802
|
+
<tr>
|
803
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +indy +jit [darwin-x86_64]</th>
|
804
|
+
</tr>
|
805
|
+
<tr>
|
806
|
+
<th>Library</th>
|
807
|
+
<th>Slower geometric mean</th>
|
808
|
+
</tr>
|
809
|
+
<tr>
|
810
|
+
<td>pairing_heap</td>
|
811
|
+
<td>1</td>
|
812
|
+
</tr>
|
813
|
+
<tr>
|
814
|
+
<td>Fibonacci</td>
|
815
|
+
<td>1.222x slower</td>
|
816
|
+
</tr>
|
817
|
+
<tr>
|
818
|
+
<td>lazy_priority_queue</td>
|
819
|
+
<td>1.394x slower</td>
|
411
820
|
</tr>
|
412
821
|
</table>
|
413
822
|
|
823
|
+
#### Change priority not required
|
824
|
+
<table>
|
825
|
+
<tr>
|
826
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin21]</th>
|
827
|
+
</tr>
|
828
|
+
<tr>
|
829
|
+
<th>Library</th>
|
830
|
+
<th>Slower geometric mean</th>
|
831
|
+
</tr>
|
832
|
+
<tr>
|
833
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
834
|
+
<td>1</td>
|
835
|
+
</tr>
|
836
|
+
<tr>
|
837
|
+
<td>pairing_heap (PairingHeap)</td>
|
838
|
+
<td>1.209</td>
|
839
|
+
</tr>
|
840
|
+
<tr>
|
841
|
+
<td>rb_heap</td>
|
842
|
+
<td>1.954</td>
|
843
|
+
</tr>
|
844
|
+
<tr>
|
845
|
+
<td>lazy_priority_queue</td>
|
846
|
+
<td>2.235x slower</td>
|
847
|
+
</tr>
|
848
|
+
<tr>
|
849
|
+
<td>Fibonacci</td>
|
850
|
+
<td>2.588x slower</td>
|
851
|
+
</tr>
|
852
|
+
<tr>
|
853
|
+
<th colspan="4">ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) +YJIT [x86_64-darwin21]</th>
|
854
|
+
</tr>
|
855
|
+
<tr>
|
856
|
+
<th>Library</th>
|
857
|
+
<th>Slower geometric mean</th>
|
858
|
+
</tr>
|
859
|
+
<tr>
|
860
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
861
|
+
<td>1</td>
|
862
|
+
</tr>
|
863
|
+
<tr>
|
864
|
+
<td>pairing_heap (PairingHeap)</td>
|
865
|
+
<td>1.273x slower</td>
|
866
|
+
</tr>
|
867
|
+
<tr>
|
868
|
+
<td>Fibonacci</td>
|
869
|
+
<td>1.590x slower</td>
|
870
|
+
</tr>
|
871
|
+
<tr>
|
872
|
+
<td>rb_heap</td>
|
873
|
+
<td>1.666x slower</td>
|
874
|
+
</tr>
|
875
|
+
<tr>
|
876
|
+
<td>lazy_priority_queue</td>
|
877
|
+
<td>2.230x slower</td>
|
878
|
+
</tr>
|
879
|
+
<tr>
|
880
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +jit [darwin-x86_64]</th>
|
881
|
+
</tr>
|
882
|
+
<tr>
|
883
|
+
<th>Library</th>
|
884
|
+
<th>Slower geometric mean</th>
|
885
|
+
</tr>
|
886
|
+
<tr>
|
887
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
888
|
+
<td>1</td>
|
889
|
+
</tr>
|
890
|
+
<tr>
|
891
|
+
<td>pairing_heap (PairingHeap)</td>
|
892
|
+
<td>1.296</td>
|
893
|
+
</tr>
|
894
|
+
<tr>
|
895
|
+
<td>lazy_priority_queue</td>
|
896
|
+
<td>1.607x slower</td>
|
897
|
+
</tr>
|
898
|
+
<tr>
|
899
|
+
<td>rb_heap</td>
|
900
|
+
<td>1.710</td>
|
901
|
+
</tr>
|
902
|
+
<tr>
|
903
|
+
<td>Fibonacci</td>
|
904
|
+
<td>2.452x slower</td>
|
905
|
+
</tr>
|
906
|
+
<tr>
|
907
|
+
<th colspan="4">jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 16.0.1+9-24 on 16.0.1+9-24 +indy +jit [darwin-x86_64]</th>
|
908
|
+
</tr>
|
909
|
+
<tr>
|
910
|
+
<th>Library</th>
|
911
|
+
<th>Slower geometric mean</th>
|
912
|
+
</tr>
|
913
|
+
<tr>
|
914
|
+
<td>pairing_heap (SimplePairingHeap)</td>
|
915
|
+
<td>1</td>
|
916
|
+
</tr>
|
917
|
+
<tr>
|
918
|
+
<td>pairing_heap (PairingHeap)</td>
|
919
|
+
<td>1.353x slower</td>
|
920
|
+
</tr>
|
921
|
+
<tr>
|
922
|
+
<td>rb_heap</td>
|
923
|
+
<td>1.522x slower</td>
|
924
|
+
</tr>
|
925
|
+
<tr>
|
926
|
+
<td>Fibonacci</td>
|
927
|
+
<td>1.730x slower</td>
|
928
|
+
</tr>
|
929
|
+
<tr>
|
930
|
+
<td>lazy_priority_queue</td>
|
931
|
+
<td>2.044x slower</td>
|
932
|
+
</tr>
|
933
|
+
</table>
|
414
934
|
## Development
|
415
935
|
|
416
936
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/pairing_heap/version.rb
CHANGED
data/lib/pairing_heap.rb
CHANGED
@@ -1,6 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module PairingHeap
|
4
|
+
module MergePairs
|
5
|
+
# Non-recursive implementation of method described in https://en.wikipedia.org/wiki/Pairing_heap#delete-min
|
6
|
+
def merge_pairs(heaps)
|
7
|
+
return nil if heaps.nil?
|
8
|
+
return heaps if heaps.next_sibling.nil?
|
9
|
+
|
10
|
+
# [H1, H2, H3, H4, H5, H6, H7] => [H1H2, H3H4, H5H6, H7]
|
11
|
+
stack = []
|
12
|
+
current = heaps
|
13
|
+
while current
|
14
|
+
prev = current
|
15
|
+
current = current.next_sibling
|
16
|
+
unless current
|
17
|
+
stack << prev
|
18
|
+
break
|
19
|
+
end
|
20
|
+
next_val = current.next_sibling
|
21
|
+
stack << meld(prev, current)
|
22
|
+
current = next_val
|
23
|
+
end
|
24
|
+
|
25
|
+
# [H1H2, H3H4, H5H6, H7]
|
26
|
+
# [H1H2, H3H4, H5H67]
|
27
|
+
# [H1H2, H3H45H67]
|
28
|
+
# [H1H2H3H45H67]
|
29
|
+
# return H1H2H3H45H67
|
30
|
+
while true
|
31
|
+
right = stack.pop
|
32
|
+
return right if stack.empty?
|
33
|
+
|
34
|
+
left = stack.pop
|
35
|
+
stack << meld(left, right)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
private_constant :MergePairs
|
40
|
+
|
4
41
|
# Pairing heap data structure implementation
|
5
42
|
# @see https://en.wikipedia.org/wiki/Pairing_heap
|
6
43
|
class PairingHeap
|
@@ -14,6 +51,18 @@ module PairingHeap
|
|
14
51
|
@prev_sibling = prev_sibling
|
15
52
|
@next_sibling = next_sibling
|
16
53
|
end
|
54
|
+
|
55
|
+
def remove_from_parents_list!
|
56
|
+
if self.prev_sibling
|
57
|
+
self.prev_sibling.next_sibling = self.next_sibling
|
58
|
+
self.next_sibling.prev_sibling = self.prev_sibling if self.next_sibling
|
59
|
+
elsif self.parent.subheaps.equal?(self)
|
60
|
+
self.parent.subheaps = self.next_sibling
|
61
|
+
self.next_sibling.prev_sibling = nil if self.next_sibling
|
62
|
+
end
|
63
|
+
self.prev_sibling = nil
|
64
|
+
self.next_sibling = nil
|
65
|
+
end
|
17
66
|
end
|
18
67
|
private_constant :Node
|
19
68
|
|
@@ -46,6 +95,10 @@ module PairingHeap
|
|
46
95
|
@root&.elem
|
47
96
|
end
|
48
97
|
|
98
|
+
def peek_priority
|
99
|
+
[@root&.elem, @root&.priority]
|
100
|
+
end
|
101
|
+
|
49
102
|
# Time Complexity: O(1)
|
50
103
|
# @return [Boolean]
|
51
104
|
def empty?
|
@@ -85,6 +138,12 @@ module PairingHeap
|
|
85
138
|
end
|
86
139
|
alias dequeue pop
|
87
140
|
|
141
|
+
def pop_priority
|
142
|
+
node = @root
|
143
|
+
pop
|
144
|
+
[node.elem, node.priority]
|
145
|
+
end
|
146
|
+
|
88
147
|
# Changes a priority of element to a more prioritary one
|
89
148
|
# Time Complexity: O(1)
|
90
149
|
# Amortized Time Complexity: o(log(N))
|
@@ -103,13 +162,13 @@ module PairingHeap
|
|
103
162
|
return if node.parent.nil?
|
104
163
|
return if @order[node.parent.priority, node.priority]
|
105
164
|
|
106
|
-
remove_from_parents_list
|
165
|
+
node.remove_from_parents_list!
|
107
166
|
@root = meld(node, @root)
|
108
167
|
@root.parent = nil
|
109
168
|
self
|
110
169
|
end
|
111
170
|
|
112
|
-
# Removes element from the
|
171
|
+
# Removes element from the heap
|
113
172
|
# Time Complexity: O(N)
|
114
173
|
# Amortized Time Complexity: O(log(N))
|
115
174
|
# @raise [ArgumentError] if the element heap is not in heap
|
@@ -122,7 +181,7 @@ module PairingHeap
|
|
122
181
|
if node.parent.nil?
|
123
182
|
@root = merge_pairs(node.subheaps)
|
124
183
|
else
|
125
|
-
remove_from_parents_list
|
184
|
+
node.remove_from_parents_list!
|
126
185
|
new_heap = merge_pairs(node.subheaps)
|
127
186
|
if new_heap
|
128
187
|
new_heap.prev_sibling = nil
|
@@ -135,20 +194,7 @@ module PairingHeap
|
|
135
194
|
end
|
136
195
|
|
137
196
|
private
|
138
|
-
|
139
|
-
def remove_from_parents_list(node)
|
140
|
-
if node.prev_sibling
|
141
|
-
node.prev_sibling.next_sibling = node.next_sibling
|
142
|
-
node.next_sibling.prev_sibling = node.prev_sibling if node.next_sibling
|
143
|
-
elsif node.parent.subheaps.equal?(node)
|
144
|
-
node.parent.subheaps = node.next_sibling
|
145
|
-
node.next_sibling.prev_sibling = nil if node.next_sibling
|
146
|
-
elsif node.next_sibling
|
147
|
-
node.next_sibling.prev_sibling = nil
|
148
|
-
end
|
149
|
-
node.prev_sibling = nil
|
150
|
-
node.next_sibling = nil
|
151
|
-
end
|
197
|
+
include MergePairs
|
152
198
|
|
153
199
|
def meld(left, right)
|
154
200
|
return right if left.nil?
|
@@ -168,42 +214,118 @@ module PairingHeap
|
|
168
214
|
child.parent = parent
|
169
215
|
parent
|
170
216
|
end
|
217
|
+
end
|
171
218
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
219
|
+
class SimplePairingHeap
|
220
|
+
class Node
|
221
|
+
attr_accessor :elem, :priority, :subheaps, :parent, :next_sibling
|
222
|
+
def initialize(elem, priority, subheaps, parent, next_sibling)
|
223
|
+
@elem = elem
|
224
|
+
@priority = priority
|
225
|
+
@subheaps = subheaps
|
226
|
+
@parent = parent
|
227
|
+
@next_sibling = next_sibling
|
228
|
+
end
|
229
|
+
end
|
230
|
+
private_constant :Node
|
176
231
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
232
|
+
# @param &block Optional heap property priority comparator. `<:=.to_proc` by default
|
233
|
+
def initialize(&block)
|
234
|
+
@root = nil
|
235
|
+
@order = block || :<=.to_proc
|
236
|
+
@size = 0
|
237
|
+
end
|
238
|
+
|
239
|
+
# Pushes element to the heap.
|
240
|
+
# Time Complexity: O(1)
|
241
|
+
# @param elem Element to be pushed
|
242
|
+
# @param priority Priority of the element
|
243
|
+
# @raise [ArgumentError] if the element is already in the heap
|
244
|
+
# @return [PairingHeap]
|
245
|
+
def push(elem, priority)
|
246
|
+
node = Node.new(elem, priority, nil, nil, nil)
|
247
|
+
@root = meld(@root, node)
|
248
|
+
@size += 1
|
249
|
+
self
|
250
|
+
end
|
251
|
+
alias enqueue push
|
252
|
+
|
253
|
+
# Returns the element at the top of the heap
|
254
|
+
# Time Complexity: O(1)
|
255
|
+
def peek
|
256
|
+
@root&.elem
|
257
|
+
end
|
258
|
+
|
259
|
+
def peek_priority
|
260
|
+
[@root&.elem, @root&.priority]
|
261
|
+
end
|
262
|
+
|
263
|
+
# Time Complexity: O(1)
|
264
|
+
# @return [Boolean]
|
265
|
+
def empty?
|
266
|
+
@root.nil?
|
267
|
+
end
|
268
|
+
|
269
|
+
# Time Complexity: O(1)
|
270
|
+
# @return [Boolean]
|
271
|
+
def any?
|
272
|
+
!@root.nil?
|
273
|
+
end
|
274
|
+
|
275
|
+
# Time Complexity: O(1)
|
276
|
+
# @return [Integer]
|
277
|
+
def size
|
278
|
+
@size
|
279
|
+
end
|
280
|
+
alias length size
|
281
|
+
|
282
|
+
# Removes element from the top of the heap
|
283
|
+
# Time Complexity: O(N)
|
284
|
+
# Amortized time Complexity: O(log(N))
|
285
|
+
# @raise [ArgumEntError] if the heap is empty
|
286
|
+
# @return [PairingHeap]
|
287
|
+
def pop
|
288
|
+
raise ArgumentError, "Cannot remove from an empty heap" if @root.nil?
|
289
|
+
@size -= 1
|
290
|
+
|
291
|
+
elem = @root.elem
|
292
|
+
@root = merge_pairs(@root.subheaps)
|
293
|
+
if @root
|
294
|
+
@root.parent = nil
|
295
|
+
@root.next_sibling = nil
|
190
296
|
end
|
297
|
+
elem
|
298
|
+
end
|
299
|
+
alias dequeue pop
|
191
300
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
while true
|
198
|
-
right = stack.pop
|
199
|
-
return right if stack.empty?
|
301
|
+
def pop_priority
|
302
|
+
node = @root
|
303
|
+
pop
|
304
|
+
[node.elem, node.priority]
|
305
|
+
end
|
200
306
|
|
201
|
-
|
202
|
-
|
307
|
+
private
|
308
|
+
include MergePairs
|
309
|
+
|
310
|
+
def meld(left, right)
|
311
|
+
return right if left.nil?
|
312
|
+
return left if right.nil?
|
313
|
+
|
314
|
+
if @order[left.priority, right.priority]
|
315
|
+
parent = left
|
316
|
+
child = right
|
317
|
+
else
|
318
|
+
parent = right
|
319
|
+
child = left
|
203
320
|
end
|
321
|
+
child.next_sibling = parent.subheaps
|
322
|
+
parent.subheaps = child
|
323
|
+
child.parent = parent
|
324
|
+
parent
|
204
325
|
end
|
205
326
|
end
|
206
327
|
|
328
|
+
|
207
329
|
# Priority queue where the smallest priority is the most prioritary
|
208
330
|
class MinPriorityQueue < PairingHeap
|
209
331
|
def initialize
|
data/pairing_heap.gemspec
CHANGED
@@ -8,14 +8,15 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Marcin Henryk Bartkowiak"]
|
9
9
|
spec.email = ["mhbartkowiak@gmail.com"]
|
10
10
|
|
11
|
-
spec.summary = "Performant priority queue in pure
|
12
|
-
spec.description = "Performant priority queue in pure
|
11
|
+
spec.summary = "Performant priority queue in pure ruby with support for changing priority"
|
12
|
+
spec.description = "Performant priority queue in pure ruby with support for changing priority using pairing heap data structure"
|
13
13
|
spec.homepage = "https://github.com/mhib/pairing_heap"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
16
16
|
|
17
|
-
spec.metadata["homepage_uri"]
|
18
|
-
spec.metadata["source_code_uri"]
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
19
|
+
spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/pairing_heap"
|
19
20
|
|
20
21
|
# Specify which files should be added to the gem when it is released.
|
21
22
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pairing_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
|
- Marcin Henryk Bartkowiak
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '13.0'
|
41
|
-
description: Performant priority queue in pure
|
41
|
+
description: Performant priority queue in pure ruby with support for changing priority
|
42
42
|
using pairing heap data structure
|
43
43
|
email:
|
44
44
|
- mhbartkowiak@gmail.com
|
@@ -65,6 +65,7 @@ licenses:
|
|
65
65
|
metadata:
|
66
66
|
homepage_uri: https://github.com/mhib/pairing_heap
|
67
67
|
source_code_uri: https://github.com/mhib/pairing_heap
|
68
|
+
documentation_uri: https://rubydoc.info/gems/pairing_heap
|
68
69
|
post_install_message:
|
69
70
|
rdoc_options: []
|
70
71
|
require_paths:
|
@@ -80,8 +81,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
81
|
- !ruby/object:Gem::Version
|
81
82
|
version: '0'
|
82
83
|
requirements: []
|
83
|
-
rubygems_version: 3.
|
84
|
+
rubygems_version: 3.3.3
|
84
85
|
signing_key:
|
85
86
|
specification_version: 4
|
86
|
-
summary: Performant priority queue in pure
|
87
|
+
summary: Performant priority queue in pure ruby with support for changing priority
|
87
88
|
test_files: []
|