第19章 二项堆
#include
#include
#include
#include
#include
typedef struct binomial_heap *heap;
struct heap_node {
void *key;
int degree;
struct heap_node *child;
struct heap_node *sibling;
struct heap_node *parent;
};
struct binomial_heap {
int (*comp) (const void *, const void *);
//这个函数是用于结点交换时通知调用
void (*on_swap) (struct heap_node *, struct heap_node *);
struct heap_node *head;
};
void swap(void *a, void *b, size_t elem_size)
{
if (a == NULL || b == NULL || a == b)
return;
char temp[elem_size]; /*变长数组 */
memcpy(temp, a, elem_size);
memcpy(a, b, elem_size);
memcpy(b, temp, elem_size);
}
void heap_node_ini(struct heap_node *x, void *key)
{
x->key = key;
x->degree = 0;
x->parent = NULL;
x->child = NULL;
x->sibling = NULL;
}
heap heap_create(int (*comp) (const void *, const void *),
void (*on_swap) (struct heap_node *, struct heap_node *))
{
heap h = malloc(sizeof(struct binomial_heap));
h->comp = comp;
h->on_swap = on_swap;
h->head = NULL;
return h;
}
//返回一个指针,它指向包含n个结点的二项堆H中具有最小关键字的结点
struct heap_node *heap_minimum(heap h)
{
struct heap_node *y = NULL;
struct heap_node *x = h->head;
void *min;
bool first = true;
while (x != NULL) {
if (first || h->comp(x->key, min) < 0) {
first = false;
min = x->key;
y = x;
}
x = x->sibling;
}
return y;
}
bool heap_is_empty(heap h)
{
return h->head == NULL;
}
//将结点y为根和z为根的树连接过来,使z成为y的父结点
void link(struct heap_node *y, struct heap_node *z)
{
y->parent = z;
y->sibling = z->child;
z->child = y;
z->degree = z->degree + 1;
}
void heap_destroy(heap h);
//将ha和hb合并成一个按度数的单调递增次序排列的链表
struct heap_node *heap_merge(heap ha, heap hb)
{
struct heap_node *pa = ha->head;
struct heap_node *pb = hb->head;
struct heap_node *head = NULL;
struct heap_node *tail = NULL;
while (pa != NULL && pb != NULL) {
if (pa->degree <= pb->degree) {
if (head == NULL) {
head = pa;
tail = pa;
pa = pa->sibling;
tail->sibling = NULL;
} else {
tail->sibling = pa;
pa = pa->sibling;
tail = tail->sibling;
tail->sibling = NULL;
}
} else {
if (head == NULL) {
head = pb;
tail = pb;
pb = pb->sibling;
tail->sibling = NULL;
} else {
tail->sibling = pb;
pb = pb->sibling;
tail = tail->sibling;
tail->sibling = NULL;
}
}
}
if (pa != NULL && pb == NULL) {
if (head == NULL) {
head = pa;
tail = pa;
} else {
tail->sibling = pa;
}
}
if (pa == NULL && pb != NULL) {
if (head == NULL) {
head = pb;
tail = pb;
} else {
tail->sibling = pb;
}
}
hb->head = NULL;
heap_destroy(hb);
return head;
}
//将hb合并到ha中
void heap_union(heap ha, heap hb)
{
//将ha和hb的根表合并成一个按度数的单调递增次序排列的链表
ha->head = heap_merge(ha, hb);
if (ha->head == NULL) {
return;
}
struct heap_node *prev = NULL;
struct heap_node *x = ha->head;
struct heap_node *next = x->sibling;
while (next != NULL) {
//情况1:x->degree!=next->degree
//情况2:x->degree==next->degree==next->sibling->degree
if ((x->degree != next->degree) ||
(next->sibling != NULL
&& next->sibling->degree == x->degree)) {
prev = x;
x = next;
} else if (ha->comp(x->key, next->key) <= 0) {
//情况3:x->degree==next->degree!=next->sibling->degree,x->key<=next->key
x->sibling = next->sibling;
link(next, x);
} else {
//情况4:x->degree==next->degree!=next->sibling->degree,next->key<=x->key
if (prev == NULL) {
ha->head = next;
} else {
prev->sibling = next;
}
link(x, next);
x = next;
}
next = x->sibling;
}
}
//反转x的孩子,随便把x的孩子的父结点置为空
void reverse_children(struct heap_node *x)
{
if (x == NULL || x->child == NULL)
return;
struct heap_node *prev = x->child;
struct heap_node *current = prev->sibling;
struct heap_node *next = NULL;
while (current != NULL) {
next = current->sibling;
current->sibling = prev;
current->parent = NULL;
prev = current;
current = next;
}
x->child->sibling = NULL;
x->child->parent = NULL;
x->child = prev;
}
//下面的过程将结点x插入二项堆中,假定结点x已被分配,且key[x]也已填有内容
void heap_insert(heap h, struct heap_node *x)
{
heap hb = heap_create(h->comp, h->on_swap);
hb->head = x;
heap_union(h, hb);
}
struct heap_node *heap_remove_minimum(heap h)
{
struct heap_node *x = h->head;
if (x == NULL)
return NULL;
struct heap_node *prev = NULL;
struct heap_node *min_prev = NULL;
void *min;
bool first = true;
while (x != NULL) {
if (first || h->comp(x->key, min) < 0) {
first = false;
min = x->key;
min_prev = prev;
}
prev = x;
x = x->sibling;
}
//删除结点x
if (min_prev == NULL) {
x = h->head;
h->head = x->sibling;
} else {
x = min_prev->sibling;
min_prev->sibling = x->sibling;
}
return x;
}
//抽取具有最小关键字的结点,并返回一个指向该结点的指针
struct heap_node *heap_extract_min(heap h)
{
struct heap_node *x = heap_remove_minimum(h);
if (x == NULL)
return NULL;
reverse_children(x);
heap hb = heap_create(h->comp, h->on_swap);
hb->head = x->child;
heap_union(h, hb);
return x;
}
//将二项堆中的某一结点x的关键字减少为一个新值k,如果k大于x的当前关键字值,直接返回
void heap_decrease_key(heap h, struct heap_node *x)
{
struct heap_node *y = x;
struct heap_node *z = y->parent;
while (z != NULL && h->comp(y->key, z->key) < 0) {
swap(&y->key, &z->key, sizeof(void *));
if (h->on_swap != NULL) {
h->on_swap(y, z);
}
y = z;
z = y->parent;
}
}
void display_node(struct heap_node *x, void (*print_key) (const void *))
{
print_key(x->key);
printf(" ");
if (x->child != NULL) {
display_node(x->child, print_key);
}
if (x->sibling != NULL) {
display_node(x->sibling, print_key);
}
}
void heap_display(heap h, void (*print_key) (const void *))
{
display_node(h->head, print_key);
printf("\n");
}
void heap_destroy(heap h)
{
while (!heap_is_empty(h)) {
struct heap_node *x = heap_extract_min(h);
free(x->key);
free(x);
}
free(h);
}
void on_swap(struct heap_node *left, struct heap_node *right)
{
printf("%d和%d发生了交换\n", *(int *)left->key,
*(int *)right->key);
}
int cmp_int(const void *p1, const void *p2)
{
const int *pa = p1;
const int *pb = p2;
if (*pa < *pb)
return -1;
if (*pa == *pb)
return 0;
return 1;
}
void print_key(const void *key)
{
const int *p = key;
printf("%d", *p);
}
int main()
{
heap h = heap_create(cmp_int, on_swap);
struct heap_node *x = NULL;
struct heap_node *parray[10];
for (int i = 0; i < 10; i++) {
struct heap_node *x = malloc(sizeof(struct heap_node));
int *ip = malloc(sizeof(int));
*ip = i;
heap_node_ini(x, ip);
heap_insert(h, x);
parray[i] = x;
}
printf("原始数据:\n");
heap_display(h, print_key);
int change_index = 5;
*(int*)parray[change_index]->key=INT_MIN;
heap_decrease_key(h, parray[change_index]);
printf("修改了第%d个结点的数据:\n", change_index);
heap_display(h, print_key);
heap hb = heap_create(cmp_int, on_swap);
for (int i = 10; i < 20; i++) {
struct heap_node *x = malloc(sizeof(struct heap_node));
int *ip = malloc(sizeof(int));
*ip = i;
heap_node_ini(x, ip);
heap_insert(hb, x);
}
heap_union(h, hb);
printf("合并了之后的数据:\n");
heap_display(h, print_key);
printf("按从小到大的顺序输出:\n");
while (!heap_is_empty(h)) {
x = heap_extract_min(h);
print_key(x->key);
printf(" ");
free(x->key);
free(x);
}
printf("\n");
heap_destroy(h);
return 0;
}