算法导论代码 第19章 二项堆

19章 二项堆

#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值