Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/lib/pairingheap.c
Line
Count
Source
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-2026, 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
29
static pairingheap_node *merge(pairingheap *heap, pairingheap_node *a,
30
                 pairingheap_node *b);
31
static pairingheap_node *merge_children(pairingheap *heap,
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
 */
41
pairingheap *
42
pairingheap_allocate(pairingheap_comparator compare, void *arg)
43
0
{
44
0
  pairingheap *heap;
45
46
0
  heap = palloc_object(pairingheap);
47
0
  pairingheap_initialize(heap, compare, arg);
48
49
0
  return heap;
50
0
}
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
 */
59
void
60
pairingheap_initialize(pairingheap *heap, pairingheap_comparator compare,
61
             void *arg)
62
0
{
63
0
  heap->ph_compare = compare;
64
0
  heap->ph_arg = arg;
65
66
0
  heap->ph_root = NULL;
67
0
}
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
 */
76
void
77
pairingheap_free(pairingheap *heap)
78
0
{
79
0
  pfree(heap);
80
0
}
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
 */
92
static pairingheap_node *
93
merge(pairingheap *heap, pairingheap_node *a, pairingheap_node *b)
94
0
{
95
0
  if (a == NULL)
96
0
    return b;
97
0
  if (b == NULL)
98
0
    return a;
99
100
  /* swap 'a' and 'b' so that 'a' is the one with larger value */
101
0
  if (heap->ph_compare(a, b, heap->ph_arg) < 0)
102
0
  {
103
0
    pairingheap_node *tmp;
104
105
0
    tmp = a;
106
0
    a = b;
107
0
    b = tmp;
108
0
  }
109
110
  /* and put 'b' as a child of 'a' */
111
0
  if (a->first_child)
112
0
    a->first_child->prev_or_parent = b;
113
0
  b->prev_or_parent = a;
114
0
  b->next_sibling = a->first_child;
115
0
  a->first_child = b;
116
117
0
  return a;
118
0
}
119
120
/*
121
 * pairingheap_add
122
 *
123
 * Adds the given node to the heap in O(1) time.
124
 */
125
void
126
pairingheap_add(pairingheap *heap, pairingheap_node *node)
127
0
{
128
0
  node->first_child = NULL;
129
130
  /* Link the new node as a new tree */
131
0
  heap->ph_root = merge(heap, heap->ph_root, node);
132
0
  heap->ph_root->prev_or_parent = NULL;
133
0
  heap->ph_root->next_sibling = NULL;
134
0
}
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
 */
143
pairingheap_node *
144
pairingheap_first(pairingheap *heap)
145
0
{
146
0
  Assert(!pairingheap_is_empty(heap));
147
148
0
  return heap->ph_root;
149
0
}
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
 */
158
pairingheap_node *
159
pairingheap_remove_first(pairingheap *heap)
160
0
{
161
0
  pairingheap_node *result;
162
0
  pairingheap_node *children;
163
164
0
  Assert(!pairingheap_is_empty(heap));
165
166
  /* Remove the root, and form a new heap of its children. */
167
0
  result = heap->ph_root;
168
0
  children = result->first_child;
169
170
0
  heap->ph_root = merge_children(heap, children);
171
0
  if (heap->ph_root)
172
0
  {
173
0
    heap->ph_root->prev_or_parent = NULL;
174
0
    heap->ph_root->next_sibling = NULL;
175
0
  }
176
177
0
  return result;
178
0
}
179
180
/*
181
 * Remove 'node' from the heap. O(log n) amortized.
182
 */
183
void
184
pairingheap_remove(pairingheap *heap, pairingheap_node *node)
185
0
{
186
0
  pairingheap_node *children;
187
0
  pairingheap_node *replacement;
188
0
  pairingheap_node *next_sibling;
189
0
  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
0
  if (node == heap->ph_root)
196
0
  {
197
0
    (void) pairingheap_remove_first(heap);
198
0
    return;
199
0
  }
200
201
  /*
202
   * Before we modify anything, remember the removed node's first_child and
203
   * next_sibling pointers.
204
   */
205
0
  children = node->first_child;
206
0
  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
0
  if (node->prev_or_parent->first_child == node)
213
0
    prev_ptr = &node->prev_or_parent->first_child;
214
0
  else
215
0
    prev_ptr = &node->prev_or_parent->next_sibling;
216
0
  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
0
  if (children)
224
0
  {
225
0
    replacement = merge_children(heap, children);
226
227
0
    replacement->prev_or_parent = node->prev_or_parent;
228
0
    replacement->next_sibling = node->next_sibling;
229
0
    *prev_ptr = replacement;
230
0
    if (next_sibling)
231
0
      next_sibling->prev_or_parent = replacement;
232
0
  }
233
0
  else
234
0
  {
235
0
    *prev_ptr = next_sibling;
236
0
    if (next_sibling)
237
0
      next_sibling->prev_or_parent = node->prev_or_parent;
238
0
  }
239
0
}
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
 */
247
static pairingheap_node *
248
merge_children(pairingheap *heap, pairingheap_node *children)
249
0
{
250
0
  pairingheap_node *curr,
251
0
         *next;
252
0
  pairingheap_node *pairs;
253
0
  pairingheap_node *newroot;
254
255
0
  if (children == NULL || children->next_sibling == NULL)
256
0
    return children;
257
258
  /* Walk the subheaps from left to right, merging in pairs */
259
0
  next = children;
260
0
  pairs = NULL;
261
0
  for (;;)
262
0
  {
263
0
    curr = next;
264
265
0
    if (curr == NULL)
266
0
      break;
267
268
0
    if (curr->next_sibling == NULL)
269
0
    {
270
      /* last odd node at the end of list */
271
0
      curr->next_sibling = pairs;
272
0
      pairs = curr;
273
0
      break;
274
0
    }
275
276
0
    next = curr->next_sibling->next_sibling;
277
278
    /* merge this and the next subheap, and add to 'pairs' list. */
279
280
0
    curr = merge(heap, curr, curr->next_sibling);
281
0
    curr->next_sibling = pairs;
282
0
    pairs = curr;
283
0
  }
284
285
  /*
286
   * Merge all the pairs together to form a single heap.
287
   */
288
0
  newroot = pairs;
289
0
  next = pairs->next_sibling;
290
0
  while (next)
291
0
  {
292
0
    curr = next;
293
0
    next = curr->next_sibling;
294
295
0
    newroot = merge(heap, newroot, curr);
296
0
  }
297
298
0
  return newroot;
299
0
}
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
309
static void
310
pairingheap_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);
323
    appendStringInfoChar(buf, '\n');
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
331
char *
332
pairingheap_dump(pairingheap *heap,
333
         void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
334
         void *opaque)
335
{
336
  StringInfoData buf;
337
338
  if (!heap->ph_root)
339
    return pstrdup("(empty)");
340
341
  initStringInfo(&buf);
342
343
  pairingheap_dump_recurse(&buf, heap->ph_root, dumpfunc, opaque, 0, NULL);
344
345
  return buf.data;
346
}
347
#endif