PostgreSQL Source Code git master
Loading...
Searching...
No Matches
binaryheap.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * binaryheap.c
4 * A simple binary heap implementation
5 *
6 * Portions Copyright (c) 2012-2026, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/common/binaryheap.c
10 *
11 *-------------------------------------------------------------------------
12 */
13
14#ifdef FRONTEND
15#include "postgres_fe.h"
16#else
17#include "postgres.h"
18#endif
19
20#ifdef FRONTEND
21#include "common/logging.h"
22#endif
23#include "lib/binaryheap.h"
24
25static void sift_down(binaryheap *heap, int node_off);
26static void sift_up(binaryheap *heap, int node_off);
27
28/*
29 * binaryheap_allocate
30 *
31 * Returns a pointer to a newly-allocated heap that has the capacity to
32 * store the given number of nodes, with the heap property defined by
33 * the given comparator function, which will be invoked with the additional
34 * argument specified by 'arg'.
35 */
38{
39 int sz;
40 binaryheap *heap;
41
42 sz = offsetof(binaryheap, bh_nodes) + sizeof(bh_node_type) * capacity;
43 heap = (binaryheap *) palloc(sz);
44 heap->bh_space = capacity;
45 heap->bh_compare = compare;
46 heap->bh_arg = arg;
47
48 heap->bh_size = 0;
49 heap->bh_has_heap_property = true;
50
51 return heap;
52}
53
54/*
55 * binaryheap_reset
56 *
57 * Resets the heap to an empty state, losing its data content but not the
58 * parameters passed at allocation.
59 */
60void
62{
63 heap->bh_size = 0;
64 heap->bh_has_heap_property = true;
65}
66
67/*
68 * binaryheap_free
69 *
70 * Releases memory used by the given binaryheap.
71 */
72void
74{
75 pfree(heap);
76}
77
78/*
79 * These utility functions return the offset of the left child, right
80 * child, and parent of the node at the given index, respectively.
81 *
82 * The heap is represented as an array of nodes, with the root node
83 * stored at index 0. The left child of node i is at index 2*i+1, and
84 * the right child at 2*i+2. The parent of node i is at index (i-1)/2.
85 */
86
87static inline int
89{
90 return 2 * i + 1;
91}
92
93static inline int
95{
96 return 2 * i + 2;
97}
98
99static inline int
101{
102 return (i - 1) / 2;
103}
104
105/*
106 * binaryheap_add_unordered
107 *
108 * Adds the given datum to the end of the heap's list of nodes in O(1) without
109 * preserving the heap property. This is a convenience to add elements quickly
110 * to a new heap. To obtain a valid heap, one must call binaryheap_build()
111 * afterwards.
112 */
113void
115{
116 if (heap->bh_size >= heap->bh_space)
117 {
118#ifdef FRONTEND
119 pg_fatal("out of binary heap slots");
120#else
121 elog(ERROR, "out of binary heap slots");
122#endif
123 }
124 heap->bh_has_heap_property = false;
125 heap->bh_nodes[heap->bh_size] = d;
126 heap->bh_size++;
127}
128
129/*
130 * binaryheap_build
131 *
132 * Assembles a valid heap in O(n) from the nodes added by
133 * binaryheap_add_unordered(). Not needed otherwise.
134 */
135void
137{
138 int i;
139
140 for (i = parent_offset(heap->bh_size - 1); i >= 0; i--)
141 sift_down(heap, i);
142 heap->bh_has_heap_property = true;
143}
144
145/*
146 * binaryheap_add
147 *
148 * Adds the given datum to the heap in O(log n) time, while preserving
149 * the heap property.
150 */
151void
153{
154 if (heap->bh_size >= heap->bh_space)
155 {
156#ifdef FRONTEND
157 pg_fatal("out of binary heap slots");
158#else
159 elog(ERROR, "out of binary heap slots");
160#endif
161 }
162 heap->bh_nodes[heap->bh_size] = d;
163 heap->bh_size++;
164 sift_up(heap, heap->bh_size - 1);
165}
166
167/*
168 * binaryheap_first
169 *
170 * Returns a pointer to the first (root, topmost) node in the heap
171 * without modifying the heap. The caller must ensure that this
172 * routine is not used on an empty heap. Always O(1).
173 */
176{
178 return heap->bh_nodes[0];
179}
180
181/*
182 * binaryheap_remove_first
183 *
184 * Removes the first (root, topmost) node in the heap and returns a
185 * pointer to it after rebalancing the heap. The caller must ensure
186 * that this routine is not used on an empty heap. O(log n) worst
187 * case.
188 */
191{
192 bh_node_type result;
193
195
196 /* extract the root node, which will be the result */
197 result = heap->bh_nodes[0];
198
199 /* easy if heap contains one element */
200 if (heap->bh_size == 1)
201 {
202 heap->bh_size--;
203 return result;
204 }
205
206 /*
207 * Remove the last node, placing it in the vacated root entry, and sift
208 * the new root node down to its correct position.
209 */
210 heap->bh_nodes[0] = heap->bh_nodes[--heap->bh_size];
211 sift_down(heap, 0);
212
213 return result;
214}
215
216/*
217 * binaryheap_remove_node
218 *
219 * Removes the nth (zero based) node from the heap. The caller must ensure
220 * that there are at least (n + 1) nodes in the heap. O(log n) worst case.
221 */
222void
224{
225 int cmp;
226
228 Assert(n >= 0 && n < heap->bh_size);
229
230 /* compare last node to the one that is being removed */
231 cmp = heap->bh_compare(heap->bh_nodes[--heap->bh_size],
232 heap->bh_nodes[n],
233 heap->bh_arg);
234
235 /* remove the last node, placing it in the vacated entry */
236 heap->bh_nodes[n] = heap->bh_nodes[heap->bh_size];
237
238 /* sift as needed to preserve the heap property */
239 if (cmp > 0)
240 sift_up(heap, n);
241 else if (cmp < 0)
242 sift_down(heap, n);
243}
244
245/*
246 * binaryheap_replace_first
247 *
248 * Replace the topmost element of a non-empty heap, preserving the heap
249 * property. O(1) in the best case, or O(log n) if it must fall back to
250 * sifting the new node down.
251 */
252void
254{
256
257 heap->bh_nodes[0] = d;
258
259 if (heap->bh_size > 1)
260 sift_down(heap, 0);
261}
262
263/*
264 * Sift a node up to the highest position it can hold according to the
265 * comparator.
266 */
267static void
269{
271
272 /*
273 * Within the loop, the node_off'th array entry is a "hole" that
274 * notionally holds node_val, but we don't actually store node_val there
275 * till the end, saving some unnecessary data copying steps.
276 */
277 while (node_off != 0)
278 {
279 int cmp;
280 int parent_off;
282
283 /*
284 * If this node is smaller than its parent, the heap condition is
285 * satisfied, and we're done.
286 */
289 cmp = heap->bh_compare(node_val,
291 heap->bh_arg);
292 if (cmp <= 0)
293 break;
294
295 /*
296 * Otherwise, swap the parent value with the hole, and go on to check
297 * the node's new parent.
298 */
301 }
302 /* Re-fill the hole */
303 heap->bh_nodes[node_off] = node_val;
304}
305
306/*
307 * Sift a node down from its current position to satisfy the heap
308 * property.
309 */
310static void
312{
314
315 /*
316 * Within the loop, the node_off'th array entry is a "hole" that
317 * notionally holds node_val, but we don't actually store node_val there
318 * till the end, saving some unnecessary data copying steps.
319 */
320 while (true)
321 {
324 int swap_off = left_off;
325
326 /* Is the right child larger than the left child? */
327 if (right_off < heap->bh_size &&
328 heap->bh_compare(heap->bh_nodes[left_off],
329 heap->bh_nodes[right_off],
330 heap->bh_arg) < 0)
332
333 /*
334 * If no children or parent is >= the larger child, heap condition is
335 * satisfied, and we're done.
336 */
337 if (left_off >= heap->bh_size ||
338 heap->bh_compare(node_val,
339 heap->bh_nodes[swap_off],
340 heap->bh_arg) >= 0)
341 break;
342
343 /*
344 * Otherwise, swap the hole with the child that violates the heap
345 * property; then go on to check its children.
346 */
347 heap->bh_nodes[node_off] = heap->bh_nodes[swap_off];
349 }
350 /* Re-fill the hole */
351 heap->bh_nodes[node_off] = node_val;
352}
void binaryheap_remove_node(binaryheap *heap, int n)
Definition binaryheap.c:223
void binaryheap_build(binaryheap *heap)
Definition binaryheap.c:136
void binaryheap_replace_first(binaryheap *heap, bh_node_type d)
Definition binaryheap.c:253
void binaryheap_reset(binaryheap *heap)
Definition binaryheap.c:61
bh_node_type binaryheap_first(binaryheap *heap)
Definition binaryheap.c:175
void binaryheap_add(binaryheap *heap, bh_node_type d)
Definition binaryheap.c:152
bh_node_type binaryheap_remove_first(binaryheap *heap)
Definition binaryheap.c:190
static void sift_down(binaryheap *heap, int node_off)
Definition binaryheap.c:311
static int parent_offset(int i)
Definition binaryheap.c:100
static void sift_up(binaryheap *heap, int node_off)
Definition binaryheap.c:268
static int right_offset(int i)
Definition binaryheap.c:94
static int left_offset(int i)
Definition binaryheap.c:88
void binaryheap_free(binaryheap *heap)
Definition binaryheap.c:73
void binaryheap_add_unordered(binaryheap *heap, bh_node_type d)
Definition binaryheap.c:114
binaryheap * binaryheap_allocate(int capacity, binaryheap_comparator compare, void *arg)
Definition binaryheap.c:37
#define binaryheap_empty(h)
Definition binaryheap.h:65
int(* binaryheap_comparator)(bh_node_type a, bh_node_type b, void *arg)
Definition binaryheap.h:30
Datum bh_node_type
Definition binaryheap.h:23
#define Assert(condition)
Definition c.h:873
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
static int compare(const void *arg1, const void *arg2)
Definition geqo_pool.c:144
int i
Definition isn.c:77
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
void * arg
#define pg_fatal(...)
static int fb(int x)
static int cmp(const chr *x, const chr *y, size_t len)
bool bh_has_heap_property
Definition binaryheap.h:46
binaryheap_comparator bh_compare
Definition binaryheap.h:47
bh_node_type bh_nodes[FLEXIBLE_ARRAY_MEMBER]
Definition binaryheap.h:49
void * bh_arg
Definition binaryheap.h:48