Workshop o mikrokontrolérech na SKSP 2024.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
5.4 KiB

2 months ago
/*
* UCW Library -- Binomial Heaps
*
* (c) 2003 Martin Mares <mj@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
*/
/*
* This is a generic implementation of Binomial Heaps. Each time you include
* this file with parameters set in the corresponding preprocessor macros
* as described below, it generates functions for manipulating the particular
* version of the binomial heap.
*/
/***
* [[generator]]
* Interface to the generator
* --------------------------
*
* To use the binomial heaps, you need to specify:
*
* - `BH_PREFIX(x)` -- macro to add a name prefix (used on all global names
* defined by the generator). All further names mentioned
* here except for macro names will be implicitly prefixed.
*
* Then you continue by including `ucw/binheap-node.h` which defines <<struct_bh_node,struct bh_node>>
* and <<struct_bh_heap,struct bh_heap>> (both without prefix). The heap elements are always allocated by
* you and they must include `struct bh_node` which serves as a handle used for all
* the heap functions and it contains all information needed for heap-keeping.
* The heap itself is also allocated by you and it's represented by `struct bh_heap`.
*
* When you have the declaration of heap nodes, you continue with defining:
*
* - `less(p,q)` -- returns `1` if the key corresponding to `bh_node *p`
* is less than the one corresponding to `*q`.
*
* Then specify what operations you request:
*
* - `init(heap\*)` -- initialize the heap (always defined).
* - `insert(heap\*, node\*)` -- insert the node to the heap (`BH_WANT_INSERT`).
* - `node\* findmin(heap\*)` -- find node with minimum key (`BH_WANT_FINDMIN`).
* - `node\* deletemin(heap\*)` -- findmin and delete the node (`BH_WANT_DELETEMIN`).
*
* Then include `ucw/binheap.h` and voila, you have a binomial heap
* suiting all your needs (at least those which you've revealed :) ).
*
* You also get a iterator macro at no extra charge:
*
* BH_FOR_ALL(bh_prefix, heap*, variable)
* {
* // node* variable gets declared automatically
* do_something_with_node(variable);
* // use BH_BREAK and BH_CONTINUE instead of break and continue
* // you must not alter contents of the binomial heap here
* }
* BH_END_FOR;
*
* After including this file, all parameter macros are automatically undef'd.
***/
#define BH_NODE struct bh_node
#define BH_HEAP struct bh_heap
static void
BH_PREFIX(merge)(BH_NODE *a, BH_NODE *b)
{
BH_NODE **pp = &a->first_son;
BH_NODE *q = b->first_son;
BH_NODE *p, *r, *s;
while ((p = *pp) && q)
{
/* p,q are the next nodes of a,b; pp points to where p is linked */
if (p->order < q->order) /* p is smaller => skip it */
pp = &p->next_sibling;
else if (p->order > q->order) /* q is smaller => insert it before p */
{
r = q;
q = q->next_sibling;
r->next_sibling = p;
*pp = r;
pp = &r->next_sibling;
}
else /* p and q are of the same order => need to merge them */
{
if (BH_PREFIX(less)(p, q)) /* we'll hang r below s */
{
r = q;
s = p;
}
else
{
r = p;
s = q;
}
*pp = p->next_sibling; /* unlink p,q from their lists */
q = q->next_sibling;
if (s->last_son) /* merge r to s, increasing order */
s->last_son->next_sibling = r;
else
s->first_son = r;
s->last_son = r;
s->order++;
r->next_sibling = NULL;
if (!q || q->order > s->order) /* put the result into the b's list if possible */
{
s->next_sibling = q;
q = s;
}
else /* otherwise put the result to the a's list */
{
p = s->next_sibling = *pp;
*pp = s;
if (p && p->order == s->order) /* 3-collision */
pp = &s->next_sibling;
}
}
}
if (!p)
*pp = q;
}
#ifdef BH_WANT_INSERT
static void
BH_PREFIX(insert)(BH_HEAP *heap, BH_NODE *a)
{
BH_NODE sh;
sh.first_son = a;
a->first_son = a->last_son = a->next_sibling = NULL;
a->order = 0;
BH_PREFIX(merge)(&heap->root, &sh);
}
#endif
#ifdef BH_WANT_FINDMIN
static BH_NODE *
BH_PREFIX(findmin)(BH_HEAP *heap)
{
BH_NODE *p, *best;
best = NULL;
for (p=heap->root.first_son; p; p=p->next_sibling)
if (!best || BH_PREFIX(less)(p, best))
best = p;
return best;
}
#endif
#ifdef BH_WANT_DELETEMIN
static BH_NODE *
BH_PREFIX(deletemin)(BH_HEAP *heap)
{
BH_NODE *p, **pp, **bestp;
bestp = NULL;
for (pp=&heap->root.first_son; p=*pp; pp=&p->next_sibling)
if (!bestp || BH_PREFIX(less)(p, *bestp))
bestp = pp;
if (!bestp)
return NULL;
p = *bestp;
*bestp = p->next_sibling;
BH_PREFIX(merge)(&heap->root, p);
return p;
}
#endif
static inline void
BH_PREFIX(init)(BH_HEAP *heap)
{
bzero(heap, sizeof(*heap));
}
#ifndef BH_FOR_ALL
#define BH_FOR_ALL(bh_px, bh_heap, bh_var) \
do { \
struct bh_node *bh_stack[32]; \
uint bh_sp = 0; \
if (bh_stack[0] = (bh_heap)->root.first_son) \
bh_sp++; \
while (bh_sp) { \
struct bh_node *bh_var = bh_stack[--bh_sp]; \
if (bh_var->next_sibling) \
bh_stack[bh_sp++] = bh_var->next_sibling; \
if (bh_var->first_son) \
bh_stack[bh_sp++] = bh_var->first_son;
#define BH_END_FOR \
} \
} while (0)
#define BH_BREAK { bh_sp=0; break; }
#define BH_CONTINUE continue
#endif
#undef BH_PREFIX
#undef BH_NODE
#undef BH_HEAP
#undef BH_WANT_INSERT
#undef BH_WANT_FINDMIN
#undef BH_WANT_DELETEMIN