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

本文介绍了一种高效的数据结构——二项堆的C语言实现,包括创建、合并、插入节点、提取最小值等核心操作,并通过实例展示了二项堆的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}


目录(Table of Contents) 前言(Preface) 第一部分(Part I) 基础(Foundations) 第一 计算中算法的角色(The Role of Algorithms in Computing) 第二 开始(Getting Started) 第三 函数的增长率(Growth of Functions) 第四 递归(Recurrences) 第五 概率分析与随机化算法(Probabilistic Analysis and Randomized Algorithms) 第二部分(Part II) 排序与顺序统计(Sorting and Order Statistics) 第六 排序(Heapsort) 第七快速排序(Quicksort) 第八 线性时间中的排序(Sorting in Linear Time) 第九 中值与顺序统计(Medians and Order Statistics) 第三部分(Part III) 数据结构(Data Structures) 第十 基本的数据结构(Elementary Data Structures) 第十一 散列表(Hash Tables) 第十二 二叉查找树(Binary Search Trees) 第十三 红-黑树(Red-Black Trees) 第十四 扩充的数据结构(Augmenting Data Structures) 第四部分(Part IV) 高级的设计与分析技术(Advanced Design and Analysis Techniques) 第十五 动态规划(Dynamic Programming) 第十六 贪婪算法(Greedy Algorithms) 第十七 分摊分析(Amortized Analysis) 第五部分(Part V) 高级的数据结构(Advanced Data Structures) 第十八 B-树(B-Trees) 第十九 二项(Binomial Heaps) 第二十 斐波纳契(Fibonacci Heaps) 第二十一 不相交集的数据结构(Data Structures for Disjoint Sets) 第六部分(Part VI) 图算法(Graph Algorithms) 第二十二 基本的图算法(Elementary Graph Algorithms) 第二十三 最小生成树(Minimum Spanning Trees) 第二十四单源最短路径(Single-Source Shortest Paths) 第二十五 全对的最短路径(All-Pairs Shortest Paths) 第二十六 最大流(Maximum Flow) 第七部分(Part VII) 精选的主题(Selected Topics) 第二十七 排序网络(Sorting Networks) 第二十八矩阵运算(Matrix Operations) 第二十九 线性规划(Linear Programming) 第三十 多项式与快速傅里叶变换(Polynomials and the FFT) 第三十一 数论算法(Number-Theoretic Algorithms) 第三十二 字符串匹配(String Matching) 第三十三 计算几何学(Computational Geometry) 第三十四 NP-完备性(NP-Completeness) 第三十五 近似算法(Approximation Algorithms) 第八部分(Part VIII) 附录:数学背景(Mathematical Background) 附录A 求和(Summations) 附录B 集合,等等。(Sets, Etc.) 附录C 计数与概率(Counting and Probability) 参考文献(Bibliography) 索引(Index)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值