* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*-------------------------------------------------------------------------
*
* pairingheap.cpp
* 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.
*
* IDENTIFICATION
* src/common/backend/lib/pairingheap.cpp
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "lib/pairingheap.h"
#define HEAP_NODE_SWAP(a, b) \
{ \
pairingheap_node *tmp; \
tmp = (a); \
(a) = (b); \
(b) = tmp; \
}
#define HEAP_NODE_ADD_FIRSTCHILDREN(a, b) \
{ \
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); \
}
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 = (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;
if (heap->ph_compare(a, b, heap->ph_arg) < 0)
HEAP_NODE_SWAP(a, b);
HEAP_NODE_ADD_FIRSTCHILDREN(a, 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;
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));
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;
next = children;
pairs = NULL;
for (;;) {
curr = next;
if (curr == NULL)
break;
if (curr->next_sibling == NULL) {
curr->next_sibling = pairs;
pairs = curr;
break;
}
next = curr->next_sibling->next_sibling;
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