第20章 斐波那契堆
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <stdlib.h>
typedef struct fib_heap *heap;
struct heap_node {
void *key;
int degree;
bool mark;
struct heap_node *child;
struct heap_node *left;
struct heap_node *right;
struct heap_node *parent;
};
struct fib_heap {
int (*comp) (const void *, const void *);
struct heap_node *min;
int num;
};
void heap_node_ini(struct heap_node *x, void *key)
{
x->key = key;
x->degree = 0;
x->mark = false;
x->parent = NULL;
x->child = NULL;
x->left = x;
x->right = x;
}
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);
}
heap heap_create(int (*comp) (const void *, const void *))
{
heap h = malloc(sizeof(struct fib_heap));
h->comp = comp;
h->num = 0;
h->min = NULL;
return h;
}
//删除结点,如果只有x一个结点的话,这个函数无效
void list_delete(struct heap_node **pos, struct heap_node *x)
{
if (x->right == x) //只有一个结点
{
*pos = NULL;
return;
}
x->left->right = x->right;
x->right->left = x->left;
if (*pos == x) {
*pos = x->right;
}
}
//插入结点x到pos的左边,如果pos为空,pos=x
void list_insert(struct heap_node **pos, struct heap_node *x)
{
if (*pos == NULL) {
*pos = x;
x->left = x;
x->right = x;
} else {
x->left = (*pos)->left;
(*pos)->left->right = x;
x->right = (*pos);
(*pos)->left = x;
}
}
void add_root(heap h, struct heap_node *x)
{
list_insert(&h->min, x);
x->parent = NULL;
x->mark = false;
if (h->comp(x->key, h->min->key) < 0) {
h->min = x;
}
}
//下面的过程将结点x插入斐波那契堆中,假定结点x已被分配,且key[x]也已填有内容
void heap_insert(heap h, struct heap_node *x)
{
x->degree = 0;
x->parent = NULL;
x->child = NULL;
x->left = x;
x->right = x;
add_root(h, x);
++h->num;
}
//最小结点
struct heap_node *heap_minimum(heap h)
{
return h->min;
}
void heap_destroy(heap h);
//将另一个斐波那契堆合并到当前堆,另一堆合并到当前最小结点的右边
void heap_union(heap ha, heap hb)
{
if (hb == NULL || hb->min == NULL) {
return;
}
if (ha->min == NULL) {
ha->min = hb->min;
} else {
//最小结点的右边结点
struct heap_node *ha_min_right = ha->min->right;
ha->min->right = hb->min;
//另一个堆最小结点的左结点,即最后一个结点
struct heap_node *hb_min_left = hb->min->left;
hb->min->left = ha->min;
hb_min_left->right = ha_min_right;
ha_min_right->left = hb_min_left;
}
if (ha->min == NULL
|| (hb->min != NULL && ha->comp(hb->min->key, ha->min->key) < 0)) {
ha->min = hb->min;
}
ha->num += hb->num;
hb->min = NULL;
heap_destroy(hb);
}
void link(heap h, struct heap_node *y, struct heap_node *x)
{
list_delete(&h->min, y);
list_insert(&x->child, y);
y->parent = x;
y->mark = false;
++x->degree;
}
//合并根表
void consolidate(heap h)
{
if (h->min == NULL)
return;
int D = floor(log(h->num) / log(1.618)); //计算D值
struct heap_node *A[D];
for (int i = 0; i < D; i++) {
A[i] = NULL;
}
struct heap_node *x = NULL;
struct heap_node *y = NULL;
int d;
struct heap_node *w = h->min;
struct heap_node *end = h->min->left;
bool loop_flag = true;
while (loop_flag) {
x = w;
if (w != end) {
w = w->right;
} else {
loop_flag = false; //w到达最后一个结点,循环结束
}
d = x->degree;
while (A[d] != NULL) {
y = A[d];
if (h->comp(x->key, y->key) > 0) {
swap(&x, &y, sizeof(struct heap_node *));
}
link(h, y, x);
A[d] = NULL;
++d;
}
A[d] = x;
}
h->min = NULL;
for (int i = 0; i < D; ++i) {
if (A[i] != NULL) {
add_root(h, A[i]);
}
}
}
//抽取具有最小关键字的结点,并返回一个指向该结点的指针
struct heap_node *heap_extract_min(heap h)
{
struct heap_node *z = h->min;
if (z == NULL)
return NULL;
struct heap_node *x = NULL;
while (z->degree > 0) {
x = z->child;
if (x->right == x) {
z->child = NULL;
} else {
z->child = z->child->right;
}
list_delete(&z->child, x);
add_root(h, x);
--z->degree;
}
if (z == z->right) {
list_delete(&h->min, z);
} else {
list_delete(&h->min, z);
consolidate(h);
}
--h->num;
return z;
}
void cut(heap h, struct heap_node *x, struct heap_node *y)
{
list_delete(&y->child, x);
add_root(h, x);
--y->degree;
}
void cascading_cut(heap h, struct heap_node *y)
{
struct heap_node *z = y->parent;
if (z == NULL)
return;
if (y->mark == false) {
y->mark = true;
} else {
cut(h, y, z);
cascading_cut(h, z);
}
}
//将斐波那契堆中的某一结点x的关键字减少为一个新值k
void heap_decrease_key(heap h, struct heap_node *x)
{
struct heap_node *y = x->parent;
if (y != NULL && h->comp(x->key, y->key) < 0) {
cut(h, x, y);
cascading_cut(h, y);
}
if (h->comp(x->key, h->min->key) < 0) {
h->min = x;
}
}
bool heap_is_empty(heap h)
{
return h->min == NULL;
}
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 heap_display(heap h, void (*print_key) (const void *))
{
if (h->min == NULL)
return;
struct heap_node *x = h->min;
bool loop_flag = true;
struct heap_node *end = h->min->left;
while (loop_flag) {
print_key(x->key);
printf(" ");
if (x != end) {
x = x->right;
} else {
loop_flag = false;
}
}
printf("\n");
}
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);
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);
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;
}