-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpairing_heap.cr
161 lines (134 loc) · 3.13 KB
/
pairing_heap.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
require "./priority_queue"
module PairingHeap
class Heap(K, V)
property size
private property root : Node(K, V)?
def initialize
@size = 0
@root = nil
end
def find_min
return nil if empty?
root
end
def insert(key : K, value : V)
node = Node(K, V).new(key, value)
@size += 1
@root = merge(root, node)
node
end
def delete_min
if r = root
delete(r)
end
end
def delete(node : Node(K, V))
key = node.key
value = node.value
r = root
if node == r
@root = collapse(node.child)
else
node.unlink
@root = merge(root, collapse(node.child))
end
@size -= 1
{key, value}
end
def merge(a : Node(K, V) | Nil, b : Node(K, V) | Nil)
return b if a.nil?
return a if b.nil?
return a if a == b
if a.key < b.key
parent = a
child = b
else
parent = b
child = a
end
parent.prepend_child(child)
# TODO: Investigate: Tests pass even if these are not cleared?!?
parent.next = nil
parent.prev = nil
parent
end
def decrease_key(node : Node(K, V), new_key : K)
raise "New key must be < old key but wasn't" if node.key < new_key
node.key = new_key
return if node == root
node.unlink
@root = merge(root, node)
end
def clear
@size = 0
@root = nil
end
def empty?
@size == 0
end
private def collapse(node)
return nil unless node
# Collapse uses two phases:
# First merge every two nodes with each other, and store a
# reference to the previous pair in prev.
n = node
tail = nil
while n
a = n
b = a.next
if b
n = b.next
result = merge(a, b)
result.prev = tail
tail = result
else
a.prev = tail
tail = a
break
end
end
# Then merge all pairs.
result = nil
while tail
n = tail.prev
result = merge(result, tail)
tail = n
end
result
end
class Node(K, V)
protected property child : Node(K, V) | Nil
protected property next : Node(K, V) | Nil
protected property prev : Node(K, V) | Nil
property key : K
property value : V
def initialize(key : K, value : V)
@key = key
@value = value
end
def prepend_child(new_child)
new_child.next = child
if ch = child
ch.prev = new_child
end
# note that the first element on each level have pointer to parent:
new_child.prev = self
@child = new_child
end
def unlink
# All nodes but the root has a prev, and the root is never
# unlinked, just dereferenced.
prev = self.prev.not_nil!
if prev.child == self # ie, prev references the parent.
prev.child = self.next
else
prev.next = self.next
end
if n = self.next
n.prev = prev
end
self
end
end
end
end