PostgreSQL Source Code git master
pairingheap.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pairingheap.c
4 * A Pairing Heap implementation
5 *
6 * A pairing heap is a data structure that's useful for implementing
7 * priority queues. It is simple to implement, and provides amortized O(1)
8 * insert and find-min operations, and amortized O(log n) delete-min.
9 *
10 * The pairing heap was first described in this paper:
11 *
12 * Michael L. Fredman, Robert Sedgewick, Daniel D. Sleator, and Robert E.
13 * Tarjan. 1986.
14 * The pairing heap: a new form of self-adjusting heap.
15 * Algorithmica 1, 1 (January 1986), pages 111-129. DOI: 10.1007/BF01840439
16 *
17 * Portions Copyright (c) 2012-2025, PostgreSQL Global Development Group
18 *
19 * IDENTIFICATION
20 * src/backend/lib/pairingheap.c
21 *
22 *-------------------------------------------------------------------------
23 */
24
25#include "postgres.h"
26
27#include "lib/pairingheap.h"
28
32 pairingheap_node *children);
33
34/*
35 * pairingheap_allocate
36 *
37 * Returns a pointer to a newly-allocated heap, with the heap property defined
38 * by the given comparator function, which will be invoked with the additional
39 * argument specified by 'arg'.
40 */
43{
44 pairingheap *heap;
45
46 heap = (pairingheap *) palloc(sizeof(pairingheap));
48
49 return heap;
50}
51
52/*
53 * pairingheap_initialize
54 *
55 * Same as pairingheap_allocate(), but initializes the pairing heap in-place
56 * rather than allocating a new chunk of memory. Useful to store the pairing
57 * heap in a shared memory.
58 */
59void
61 void *arg)
62{
63 heap->ph_compare = compare;
64 heap->ph_arg = arg;
65
66 heap->ph_root = NULL;
67}
68
69/*
70 * pairingheap_free
71 *
72 * Releases memory used by the given pairingheap.
73 *
74 * Note: The nodes in the heap are not freed!
75 */
76void
78{
79 pfree(heap);
80}
81
82/*
83 * A helper function to merge two subheaps into one.
84 *
85 * The subheap with smaller value is put as a child of the other one (assuming
86 * a max-heap).
87 *
88 * The next_sibling and prev_or_parent pointers of the input nodes are
89 * ignored. On return, the returned node's next_sibling and prev_or_parent
90 * pointers are garbage.
91 */
92static pairingheap_node *
94{
95 if (a == NULL)
96 return b;
97 if (b == NULL)
98 return a;
99
100 /* swap 'a' and 'b' so that 'a' is the one with larger value */
101 if (heap->ph_compare(a, b, heap->ph_arg) < 0)
102 {
103 pairingheap_node *tmp;
104
105 tmp = a;
106 a = b;
107 b = tmp;
108 }
109
110 /* and put 'b' as a child of 'a' */
111 if (a->first_child)
112 a->first_child->prev_or_parent = b;
113 b->prev_or_parent = a;
114 b->next_sibling = a->first_child;
115 a->first_child = b;
116
117 return a;
118}
119
120/*
121 * pairingheap_add
122 *
123 * Adds the given node to the heap in O(1) time.
124 */
125void
127{
128 node->first_child = NULL;
129
130 /* Link the new node as a new tree */
131 heap->ph_root = merge(heap, heap->ph_root, node);
132 heap->ph_root->prev_or_parent = NULL;
133 heap->ph_root->next_sibling = NULL;
134}
135
136/*
137 * pairingheap_first
138 *
139 * Returns a pointer to the first (root, topmost) node in the heap without
140 * modifying the heap. The caller must ensure that this routine is not used on
141 * an empty heap. Always O(1).
142 */
145{
147
148 return heap->ph_root;
149}
150
151/*
152 * pairingheap_remove_first
153 *
154 * Removes the first (root, topmost) node in the heap and returns a pointer to
155 * it after rebalancing the heap. The caller must ensure that this routine is
156 * not used on an empty heap. O(log n) amortized.
157 */
160{
161 pairingheap_node *result;
162 pairingheap_node *children;
163
165
166 /* Remove the root, and form a new heap of its children. */
167 result = heap->ph_root;
168 children = result->first_child;
169
170 heap->ph_root = merge_children(heap, children);
171 if (heap->ph_root)
172 {
173 heap->ph_root->prev_or_parent = NULL;
174 heap->ph_root->next_sibling = NULL;
175 }
176
177 return result;
178}
179
180/*
181 * Remove 'node' from the heap. O(log n) amortized.
182 */
183void
185{
186 pairingheap_node *children;
187 pairingheap_node *replacement;
188 pairingheap_node *next_sibling;
189 pairingheap_node **prev_ptr;
190
191 /*
192 * If the removed node happens to be the root node, do it with
193 * pairingheap_remove_first().
194 */
195 if (node == heap->ph_root)
196 {
197 (void) pairingheap_remove_first(heap);
198 return;
199 }
200
201 /*
202 * Before we modify anything, remember the removed node's first_child and
203 * next_sibling pointers.
204 */
205 children = node->first_child;
206 next_sibling = node->next_sibling;
207
208 /*
209 * Also find the pointer to the removed node in its previous sibling, or
210 * if this is the first child of its parent, in its parent.
211 */
212 if (node->prev_or_parent->first_child == node)
213 prev_ptr = &node->prev_or_parent->first_child;
214 else
215 prev_ptr = &node->prev_or_parent->next_sibling;
216 Assert(*prev_ptr == node);
217
218 /*
219 * If this node has children, make a new subheap of the children and link
220 * the subheap in place of the removed node. Otherwise just unlink this
221 * node.
222 */
223 if (children)
224 {
225 replacement = merge_children(heap, children);
226
227 replacement->prev_or_parent = node->prev_or_parent;
228 replacement->next_sibling = node->next_sibling;
229 *prev_ptr = replacement;
230 if (next_sibling)
231 next_sibling->prev_or_parent = replacement;
232 }
233 else
234 {
235 *prev_ptr = next_sibling;
236 if (next_sibling)
237 next_sibling->prev_or_parent = node->prev_or_parent;
238 }
239}
240
241/*
242 * Merge a list of subheaps into a single heap.
243 *
244 * This implements the basic two-pass merging strategy, first forming pairs
245 * from left to right, and then merging the pairs.
246 */
247static pairingheap_node *
249{
250 pairingheap_node *curr,
251 *next;
252 pairingheap_node *pairs;
253 pairingheap_node *newroot;
254
255 if (children == NULL || children->next_sibling == NULL)
256 return children;
257
258 /* Walk the subheaps from left to right, merging in pairs */
259 next = children;
260 pairs = NULL;
261 for (;;)
262 {
263 curr = next;
264
265 if (curr == NULL)
266 break;
267
268 if (curr->next_sibling == NULL)
269 {
270 /* last odd node at the end of list */
271 curr->next_sibling = pairs;
272 pairs = curr;
273 break;
274 }
275
277
278 /* merge this and the next subheap, and add to 'pairs' list. */
279
280 curr = merge(heap, curr, curr->next_sibling);
281 curr->next_sibling = pairs;
282 pairs = curr;
283 }
284
285 /*
286 * Merge all the pairs together to form a single heap.
287 */
288 newroot = pairs;
289 next = pairs->next_sibling;
290 while (next)
291 {
292 curr = next;
293 next = curr->next_sibling;
294
295 newroot = merge(heap, newroot, curr);
296 }
297
298 return newroot;
299}
300
301/*
302 * A debug function to dump the contents of the heap as a string.
303 *
304 * The 'dumpfunc' callback appends a string representation of a single node
305 * to the StringInfo. 'opaque' can be used to pass more information to the
306 * callback.
307 */
308#ifdef PAIRINGHEAP_DEBUG
309static void
310pairingheap_dump_recurse(StringInfo buf,
311 pairingheap_node *node,
312 void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
313 void *opaque,
314 int depth,
315 pairingheap_node *prev_or_parent)
316{
317 while (node)
318 {
319 Assert(node->prev_or_parent == prev_or_parent);
320
321 appendStringInfoSpaces(buf, depth * 4);
322 dumpfunc(node, buf, opaque);
324 if (node->first_child)
325 pairingheap_dump_recurse(buf, node->first_child, dumpfunc, opaque, depth + 1, node);
326 prev_or_parent = node;
327 node = node->next_sibling;
328 }
329}
330
331char *
332pairingheap_dump(pairingheap *heap,
333 void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
334 void *opaque)
335{
337
338 if (!heap->ph_root)
339 return pstrdup("(empty)");
340
342
343 pairingheap_dump_recurse(&buf, heap->ph_root, dumpfunc, opaque, 0, NULL);
344
345 return buf.data;
346}
347#endif
static int32 next
Definition: blutils.c:224
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
Assert(PointerIsAligned(start, uint64))
int b
Definition: isn.c:74
int a
Definition: isn.c:73
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
void pairingheap_remove(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:184
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:126
static pairingheap_node * merge(pairingheap *heap, pairingheap_node *a, pairingheap_node *b)
Definition: pairingheap.c:93
void pairingheap_initialize(pairingheap *heap, pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:60
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:159
void pairingheap_free(pairingheap *heap)
Definition: pairingheap.c:77
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:144
static pairingheap_node * merge_children(pairingheap *heap, pairingheap_node *children)
Definition: pairingheap.c:248
#define pairingheap_is_empty(h)
Definition: pairingheap.h:99
int(* pairingheap_comparator)(const pairingheap_node *a, const pairingheap_node *b, void *arg)
Definition: pairingheap.h:60
void * arg
static char * buf
Definition: pg_test_fsync.c:72
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:260
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
struct pairingheap_node * next_sibling
Definition: pairingheap.h:33
struct pairingheap_node * prev_or_parent
Definition: pairingheap.h:34
struct pairingheap_node * first_child
Definition: pairingheap.h:32
pairingheap_comparator ph_compare
Definition: pairingheap.h:73
void * ph_arg
Definition: pairingheap.h:74
pairingheap_node * ph_root
Definition: pairingheap.h:75