summaryrefslogtreecommitdiffstats
path: root/src/backend/lib/pairingheap.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
commit5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch)
tree739caf8c461053357daa9f162bef34516c7bf452 /src/backend/lib/pairingheap.c
parentInitial commit. (diff)
downloadpostgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz
postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/lib/pairingheap.c')
-rw-r--r--src/backend/lib/pairingheap.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/backend/lib/pairingheap.c b/src/backend/lib/pairingheap.c
new file mode 100644
index 0000000..d561df0
--- /dev/null
+++ b/src/backend/lib/pairingheap.c
@@ -0,0 +1,333 @@
+/*-------------------------------------------------------------------------
+ *
+ * pairingheap.c
+ * A Pairing Heap implementation
+ *
+ * A pairing heap is a data structure that's useful for implementing
+ * priority queues. It is simple to implement, and provides amortized O(1)
+ * insert and find-min operations, and amortized O(log n) delete-min.
+ *
+ * The pairing heap was first described in this paper:
+ *
+ * Michael L. Fredman, Robert Sedgewick, Daniel D. Sleator, and Robert E.
+ * Tarjan. 1986.
+ * The pairing heap: a new form of self-adjusting heap.
+ * Algorithmica 1, 1 (January 1986), pages 111-129. DOI: 10.1007/BF01840439
+ *
+ * Portions Copyright (c) 2012-2022, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/lib/pairingheap.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "lib/pairingheap.h"
+
+static pairingheap_node *merge(pairingheap *heap, pairingheap_node *a,
+ pairingheap_node *b);
+static pairingheap_node *merge_children(pairingheap *heap,
+ pairingheap_node *children);
+
+/*
+ * pairingheap_allocate
+ *
+ * Returns a pointer to a newly-allocated heap, with the heap property defined
+ * by the given comparator function, which will be invoked with the additional
+ * argument specified by 'arg'.
+ */
+pairingheap *
+pairingheap_allocate(pairingheap_comparator compare, void *arg)
+{
+ pairingheap *heap;
+
+ heap = (pairingheap *) palloc(sizeof(pairingheap));
+ heap->ph_compare = compare;
+ heap->ph_arg = arg;
+
+ heap->ph_root = NULL;
+
+ return heap;
+}
+
+/*
+ * pairingheap_free
+ *
+ * Releases memory used by the given pairingheap.
+ *
+ * Note: The nodes in the heap are not freed!
+ */
+void
+pairingheap_free(pairingheap *heap)
+{
+ pfree(heap);
+}
+
+/*
+ * A helper function to merge two subheaps into one.
+ *
+ * The subheap with smaller value is put as a child of the other one (assuming
+ * a max-heap).
+ *
+ * The next_sibling and prev_or_parent pointers of the input nodes are
+ * ignored. On return, the returned node's next_sibling and prev_or_parent
+ * pointers are garbage.
+ */
+static pairingheap_node *
+merge(pairingheap *heap, pairingheap_node *a, pairingheap_node *b)
+{
+ if (a == NULL)
+ return b;
+ if (b == NULL)
+ return a;
+
+ /* swap 'a' and 'b' so that 'a' is the one with larger value */
+ if (heap->ph_compare(a, b, heap->ph_arg) < 0)
+ {
+ pairingheap_node *tmp;
+
+ tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ /* and put 'b' as a child of 'a' */
+ if (a->first_child)
+ a->first_child->prev_or_parent = b;
+ b->prev_or_parent = a;
+ b->next_sibling = a->first_child;
+ a->first_child = b;
+
+ return a;
+}
+
+/*
+ * pairingheap_add
+ *
+ * Adds the given node to the heap in O(1) time.
+ */
+void
+pairingheap_add(pairingheap *heap, pairingheap_node *node)
+{
+ node->first_child = NULL;
+
+ /* Link the new node as a new tree */
+ heap->ph_root = merge(heap, heap->ph_root, node);
+ heap->ph_root->prev_or_parent = NULL;
+ heap->ph_root->next_sibling = NULL;
+}
+
+/*
+ * pairingheap_first
+ *
+ * Returns a pointer to the first (root, topmost) node in the heap without
+ * modifying the heap. The caller must ensure that this routine is not used on
+ * an empty heap. Always O(1).
+ */
+pairingheap_node *
+pairingheap_first(pairingheap *heap)
+{
+ Assert(!pairingheap_is_empty(heap));
+
+ return heap->ph_root;
+}
+
+/*
+ * pairingheap_remove_first
+ *
+ * Removes the first (root, topmost) node in the heap and returns a pointer to
+ * it after rebalancing the heap. The caller must ensure that this routine is
+ * not used on an empty heap. O(log n) amortized.
+ */
+pairingheap_node *
+pairingheap_remove_first(pairingheap *heap)
+{
+ pairingheap_node *result;
+ pairingheap_node *children;
+
+ Assert(!pairingheap_is_empty(heap));
+
+ /* Remove the root, and form a new heap of its children. */
+ result = heap->ph_root;
+ children = result->first_child;
+
+ heap->ph_root = merge_children(heap, children);
+ if (heap->ph_root)
+ {
+ heap->ph_root->prev_or_parent = NULL;
+ heap->ph_root->next_sibling = NULL;
+ }
+
+ return result;
+}
+
+/*
+ * Remove 'node' from the heap. O(log n) amortized.
+ */
+void
+pairingheap_remove(pairingheap *heap, pairingheap_node *node)
+{
+ pairingheap_node *children;
+ pairingheap_node *replacement;
+ pairingheap_node *next_sibling;
+ pairingheap_node **prev_ptr;
+
+ /*
+ * If the removed node happens to be the root node, do it with
+ * pairingheap_remove_first().
+ */
+ if (node == heap->ph_root)
+ {
+ (void) pairingheap_remove_first(heap);
+ return;
+ }
+
+ /*
+ * Before we modify anything, remember the removed node's first_child and
+ * next_sibling pointers.
+ */
+ children = node->first_child;
+ next_sibling = node->next_sibling;
+
+ /*
+ * Also find the pointer to the removed node in its previous sibling, or
+ * if this is the first child of its parent, in its parent.
+ */
+ if (node->prev_or_parent->first_child == node)
+ prev_ptr = &node->prev_or_parent->first_child;
+ else
+ prev_ptr = &node->prev_or_parent->next_sibling;
+ Assert(*prev_ptr == node);
+
+ /*
+ * If this node has children, make a new subheap of the children and link
+ * the subheap in place of the removed node. Otherwise just unlink this
+ * node.
+ */
+ if (children)
+ {
+ replacement = merge_children(heap, children);
+
+ replacement->prev_or_parent = node->prev_or_parent;
+ replacement->next_sibling = node->next_sibling;
+ *prev_ptr = replacement;
+ if (next_sibling)
+ next_sibling->prev_or_parent = replacement;
+ }
+ else
+ {
+ *prev_ptr = next_sibling;
+ if (next_sibling)
+ next_sibling->prev_or_parent = node->prev_or_parent;
+ }
+}
+
+/*
+ * Merge a list of subheaps into a single heap.
+ *
+ * This implements the basic two-pass merging strategy, first forming pairs
+ * from left to right, and then merging the pairs.
+ */
+static pairingheap_node *
+merge_children(pairingheap *heap, pairingheap_node *children)
+{
+ pairingheap_node *curr,
+ *next;
+ pairingheap_node *pairs;
+ pairingheap_node *newroot;
+
+ if (children == NULL || children->next_sibling == NULL)
+ return children;
+
+ /* Walk the subheaps from left to right, merging in pairs */
+ next = children;
+ pairs = NULL;
+ for (;;)
+ {
+ curr = next;
+
+ if (curr == NULL)
+ break;
+
+ if (curr->next_sibling == NULL)
+ {
+ /* last odd node at the end of list */
+ curr->next_sibling = pairs;
+ pairs = curr;
+ break;
+ }
+
+ next = curr->next_sibling->next_sibling;
+
+ /* merge this and the next subheap, and add to 'pairs' list. */
+
+ curr = merge(heap, curr, curr->next_sibling);
+ curr->next_sibling = pairs;
+ pairs = curr;
+ }
+
+ /*
+ * Merge all the pairs together to form a single heap.
+ */
+ newroot = pairs;
+ next = pairs->next_sibling;
+ while (next)
+ {
+ curr = next;
+ next = curr->next_sibling;
+
+ newroot = merge(heap, newroot, curr);
+ }
+
+ return newroot;
+}
+
+/*
+ * A debug function to dump the contents of the heap as a string.
+ *
+ * The 'dumpfunc' callback appends a string representation of a single node
+ * to the StringInfo. 'opaque' can be used to pass more information to the
+ * callback.
+ */
+#ifdef PAIRINGHEAP_DEBUG
+static void
+pairingheap_dump_recurse(StringInfo buf,
+ pairingheap_node *node,
+ void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
+ void *opaque,
+ int depth,
+ pairingheap_node *prev_or_parent)
+{
+ while (node)
+ {
+ Assert(node->prev_or_parent == prev_or_parent);
+
+ appendStringInfoSpaces(buf, depth * 4);
+ dumpfunc(node, buf, opaque);
+ appendStringInfoChar(buf, '\n');
+ if (node->first_child)
+ pairingheap_dump_recurse(buf, node->first_child, dumpfunc, opaque, depth + 1, node);
+ prev_or_parent = node;
+ node = node->next_sibling;
+ }
+}
+
+char *
+pairingheap_dump(pairingheap *heap,
+ void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
+ void *opaque)
+{
+ StringInfoData buf;
+
+ if (!heap->ph_root)
+ return pstrdup("(empty)");
+
+ initStringInfo(&buf);
+
+ pairingheap_dump_recurse(&buf, heap->ph_root, dumpfunc, opaque, 0, NULL);
+
+ return buf.data;
+}
+#endif