二十五、数据结构之二项队列(堆序森林)

本文深入探讨了数据结构中二项队列的概念及其在算法设计中的应用,特别是其高效的合并操作,能够达到常数时间复杂度。通过具体的代码实现,展示了二项队列的构造、合并以及插入和删除最小元素的过程。

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

  太晚了,不想码字,其实这个思想真的很精妙,对于数字的应用,逻辑思路真的很巧妙清晰,如果有时间真的可以看看(数据结构与算法分析)这本书的二项队列的思路讲解,但是我的代码已经写的很清晰了,对于d-堆永远都离不开合并操作,所以不管出于什么样的设计思想,合并永远是重中之重,而二项队列相比较前两种实现,他的合并操作完全可以达到常数时间,所以有必要研究通他的设计思想。我的合并操作的注释很清晰,完全可以理解,同时也提供了合并最小值的实现,感谢阅读。

 

#include <stdio.h>
#include <stdlib.h>

//定义最大存储7个二项式队列
#define MaxTree 7
//定义存储的最大节点数
#define Capacity 127 
//定义无穷大的数
#define Infinity 1 << 30
//定义数据类型
typedef int ElemType;
//定义二项式树的存储结构
typedef struct BinomialNode
{
	ElemType data;
	struct BinomialNode * leftChild; //定义指向的下一个左孩子
	struct BinomialNode * nextSibling; //定义指向下一个兄弟
}BinomialNode, *Position, *BinTree;

//定义二项式队列
typedef struct BinQueueNode
{
	int size; //当前队列里的节点数
	BinTree theTree[MaxTree]; //定义二项式树的集合
}BinQueueNode, *BinQueue;

//获取一个初始化的二项式队列
BinQueue Initialization()
{
	BinQueue queue;
	queue = (BinQueue)malloc(sizeof(BinQueueNode));
	for(int i = 0; i < MaxTree; i++) 
	{
		queue -> theTree[i] = NULL;
	}
	queue -> size = 0;
	return queue;
}

//组合相同长度的二项式树
BinTree Combine(BinTree t1, BinTree t2)
{
	if(t1 -> data > t2 -> data )
	{
		return Combine(t2, t1);
	}
	t2 -> nextSibling = t1 -> leftChild;
	t1 -> leftChild = t2;
	return t1;
}

//对两个二项式队列进行合并
BinQueue Merge(BinQueue q1, BinQueue q2)
{
	//当两个二项式队列相加
	if(q1 -> size + q2 -> size > Capacity)
	{
		return q1;
	}
	BinTree t1, t2, carry = NULL; //t1 : q1的二项式树, t2 : q2的二项式树 carry : t1 和 t2合并后生成的二项式树
	q1 -> size += q2 -> size;
	int i, j;
	for(i = 0 , j = 1; j <= q1 -> size; i++, j *= 2)
	{
		t1 = q1 -> theTree[i];
		t2 = q2 -> theTree[i];
		switch(!!t1 + 2 * !!t2 + 4 * !!carry)
		{
			//都不存在
			case 0:
				break;
			//只有t1存在
			case 1: 
				break;
			//只有t2存在		
			case 2:	
				q1 -> theTree[i] = t2;
				q2 -> theTree[i] = NULL;
				break;
			//t1和t2都存在	
			case 3:
				carry = Combine(t1, t2);
				q1 -> theTree[i] = q2 -> theTree[i] = NULL;
				break;
			//只有两个树合并后的树存在	
			case 4:
				q1 -> theTree[i] = carry;
				carry = NULL;
				break;
			//当前合并的树存在和t1存在	
			case 5:
				carry = Combine(t1, carry);
				q1 -> theTree[i] = NULL;
				break;
			//当前合并的树存在和t2存在
			case 6:	
				carry = Combine(t2, carry);
				q2 -> theTree[i] = NULL;
				break;
			//当三者都存在	
			case 7:
				carry = Combine(t2, carry);
				q2 -> theTree[i] = NULL;	
				break;
		}		
	}
	return q1;
}

//添加新的元素
void Insert(ElemType data, BinQueue queue)
{
	BinQueue newQueue = Initialization();
	BinTree bTree = (BinTree)malloc(sizeof(BinomialNode));
	bTree -> data = data;
	bTree -> leftChild = bTree -> nextSibling = NULL;
	newQueue -> size = 1;
	newQueue -> theTree[0] = bTree;
	Merge(queue, newQueue);
}

//删除最小元素,并返回该值
ElemType DeleteMin(BinQueue queue)
{
	if(queue -> size == 0) 
	{
		return NULL;
	}
	int minNum = Infinity;
	int minTree;
	for(int i = 0; i < MaxTree; i++)
	{
		if(queue -> theTree[i] && queue -> theTree[i] -> data < minNum)
		{
			minNum = queue -> theTree[i] -> data;
			minTree = i;
		}
	}
	BinQueue delQueue = Initialization();
	Position delTreeNode = queue -> theTree[minTree];
	Position delTree = delTreeNode -> leftChild;
	free(delTreeNode);
	queue -> theTree[minTree] = NULL;
	for(int i = minTree - 1; i >= 0; i--)
	{
		delQueue -> theTree[i] = delTree;
		delTree = delTree -> nextSibling;
		delQueue -> theTree[i] -> nextSibling = NULL;
	}
	Merge(queue, delQueue);
	queue -> size--;
	return minNum;
}

int main(void)
{
	BinQueue queue = Initialization();
	Insert(24, queue);
	Insert(21, queue);
	Insert(65, queue);
	Insert(12, queue);
	Insert(14, queue);
	Insert(16, queue);
	Insert(26, queue);
	Insert(18, queue);
	printf("%d\n", queue -> theTree[3] -> data);
	ElemType e = DeleteMin(queue);
	printf("%d %d\n", e, queue -> size);
	printf("%d\n", queue -> theTree[0] -> data);
	return 0;
}

 

1、抽象数据类型定义如下: 本程主要定义了两个类,一个用于创建节点,另一个用于创建二项。 class BinomialHeapNode { public: int key; //节点的关键字的值 int degree; //节点的度 BinomialHeapNode* sibling; //节点的右兄弟节点 BinomialHeapNode* child; //节点的最最孩子节点 BinomialHeapNode* father; //节点的双亲节点 BinomialHeapNode(int newkey) ; //构造函数,以关键字创建节点 BinomialHeapNode(); //重载构造函数,默认关键字为0 }; class BinomialHeap { public: typedef BinomialHeapNode node_t; private: static BinomialHeap heapMerge(BinomialHeap& heapA, BinomialHeap& heapB) ; //将两个二项按照根的度的递增顺构成一个新的二项 static void nodeLink(node_t* child, node_t* father) ; //将两个节点连接成二项树 public: node_t* head; //二项的头节点 BinomialHeap(); //构造函数,头结点为0 { head = 0 } BinomialHeap(node_t& node) //构造函数,以一个节点进行构造 { head = &node; } BinomialHeap(node_t* node) //构造函数,以一个节点进行构造 { head = node; } BinomialHeap(const BinomialHeap& src) //构造函数,以一个二项进行构造 { head = src.head; } inline void insertNode(node_t& node) ; //在中插入一个节点 void insertNode(node_t* node) ; //在中插入一个节点 node_t* Find_Min(); //查找关键字值最小的节点 node_t* Extract_Min(); //查找并删除关键字值最小的节点 static BinomialHeap heapUnion(BinomialHeap& heapA, BinomialHeap& heapB) ; //合并两个二项 node_t*Findnode(int key) ; //查找关键字为key的节点 inline void swapkey(node_t* source,node_t*target ) ; //交换两个节点的关键字的值 void decreaseKey(int key,int newkey) ; //减小关键字为key的节点的值为newkey void traverse(); //遍历二项 void DeleteNode(int key) ; //删除关键字为key的节点 };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值