pairing_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/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: []
|