一种二项队列实现

二项队列的优势:不仅支持insert、delete_min和merger操作,而且最坏情况下运行时间为O(logN),插入操作平均花费                                   时间为O(1)

二项队列不是一颗堆序的树,而是堆序树的集合,其中每一颗堆序树又称为二项树

二项队列性质:高度为K的二项树恰好有2的K次幂个节点

我们可以使用二项树的集合唯一地表示任意大小的优先队列

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

struct BinNode {
	int data;
	struct BinNode *firstchild;
	struct BinNode *nextsibling;
};

struct BinQueue{
	int currentsize;//当前节点数目
	struct BinNode *trees[4];
};

void print_BinQueue(struct BinQueue *H);

//初始化一个二项队列
struct BinQueue *init_BinQueue(void)
{
	struct BinQueue *H;
	int i;
	H = malloc(sizeof(struct BinQueue));
	if(NULL == H)
	{
		printf("Error: out of memory!!\n");
		return NULL;
	}
	H->currentsize = 0;
	return H;
}

//合并两个等高度二项队列
struct BinNode *merger_equal_trees(struct BinNode *H1,struct BinNode *H2)
{
	//找出哪个二项队列的根较小
	if(H1->data > H2->data)
		return merger_equal_trees(H2,H1);
	//将较小根值的二项队列的孩子指针,赋值给根值较大二项队列的兄弟指针
	H2->nextsibling = H1->firstchild;
	//将较大根值的二项队列,赋值给根值较小二项队列的孩子指针
	H1->firstchild = H2;
	return H1;
}

struct BinQueue *merger(struct BinQueue *H1,struct BinQueue *H2)
{
	struct BinNode *T1,*T2,*carry=NULL;
	int i,j;
	//首先判断是否会发生溢出
	if(H1->currentsize + H2->currentsize > 15)
	{
		printf("Error: out of capacity!!\n");
		return H1;
	}
	//更新H1的节点数
	H1->currentsize += H2->currentsize;
	//分别合并,先从低位开始
	for(i=0;i<4;i++)
	{
		T1 = H1->trees[i];
		T2 = H2->trees[i];
		//carry T2 T1所有0-7组合
		switch(!!T1 + 2*!!T2 + 4*!!carry)
		{
			case 0:
			case 1:
				break;
			case 2:
				H1->trees[i] = H2->trees[i];
				H2->trees[i] = NULL;
				break;
			case 3:
				carry = merger_equal_trees(T1,T2);
				H1->trees[i] = NULL;
				H2->trees[i] = NULL;
				break;
			case 4:
				H1->trees[i] = carry;
				carry = NULL;
				break;
			case 5:
				carry = merger_equal_trees(T1,carry);
				H1->trees[i] = NULL;
				break;
			case 6:
				carry = merger_equal_trees(T2,carry);
				H2->trees[i] = NULL;
				break;
			case 7:
				H1->trees[i] = carry;
				carry = merger_equal_trees(T1,T2);
				H2->trees[i] = NULL;
				break;
		}
	}
	return H1;
}

struct BinQueue *insert_BinQueue(int data,struct BinQueue *H)
{
	//首先创建一个只有B0的二项队列
	struct BinQueue *H1;
	int i;
	H1 = malloc(sizeof(struct BinQueue));
	if(NULL == H1)
	{
		printf("Error: out of memory!!\n");
		return NULL;
	}
	H1->trees[0] = malloc(sizeof(struct BinNode));
	if(NULL == H1->trees[0])
	{
		printf("Error: out of memory!!\n");
		return NULL;
	}
	H1->trees[0]->data = data;
	H1->trees[0]->firstchild = H1->trees[0]->nextsibling = NULL;
	H1->currentsize = 1;
	//将刚创建的二项队列和原有的二项队列合并
	H = merger(H,H1);
	return H;
}

int delete_min_BinQueue(struct BinQueue *H)
{
	int min_value = 255;//确保大于任何一个节点中数据
	int i,j;
	int min_i;
	struct BinNode *min_T,*min_BinTree;
	struct BinQueue *Delete_Queue = NULL;
	//首先判断该二项队列中节点个数
	if(0 == H->currentsize)
	{
		printf("Error: the current BinQueue is already empty!!\n");
		return -1;
	}
	//找到最小值所在的二项树
	for(i=0;i<4;i++)
	{
		if(NULL != H->trees[i] && H->trees[i]->data < min_value)
		{
			min_value = H->trees[i]->data;
			min_i = i;
			min_T = H->trees[i];
		}
	}
	//将找到的二项树从原二项队列中清除
	H->trees[min_i] = NULL;
	//创建一个新二项队列
	Delete_Queue = init_BinQueue();
	if(NULL == Delete_Queue)
	{
		printf("Error: create delete BinQueue failed\n");
		return -1;
	}
	//保存找到的二项树指针
	min_BinTree = min_T;
	//先处理最大子二项树
	Delete_Queue->trees[min_i-1] = min_T->firstchild;
	min_T = min_T->firstchild->nextsibling;
	//释放找到二项树的root节点
	free(min_BinTree);
	//将找到的二项树分解成若干个子二项树,来填充新二项队列
	for(j=min_i-2;j>=0;j--)
	{
		Delete_Queue->trees[j] = min_T;
		min_T = min_T->nextsibling;
		//将前面二项树root节点的兄弟指针置空,使他们各自独立成二项树
		Delete_Queue->trees[j+1]->nextsibling = NULL;
	}
	//将Delete BinQueue与H进行合并
	H = merger(H,Delete_Queue);
	return min_value;
}

void print_preorder(struct BinNode *T)
{
	if(NULL == T)
		return;
	printf("%d ",T->data);
	print_preorder(T->firstchild);
	print_preorder(T->nextsibling);
}

void print_BinQueue(struct BinQueue *H)
{
	int i;
	if(NULL == H)
		return;
	for(i=0;i<4;i++)
	{
		printf("B[%d]的前序遍历为:",i);
		print_preorder(H->trees[i]);
		printf("\n");
	}
}

int main(void)
{
	struct BinQueue *g_H;
	int i;
	g_H = init_BinQueue();
	for(i=1;i<=15;i++)
	{
		g_H = insert_BinQueue(i,g_H);
	}
	print_BinQueue(g_H);
	printf("-----------start delete_min()----------\n");
	delete_min_BinQueue(g_H);
	printf("-----------after delete_min()----------\n");
	print_BinQueue(g_H);
	return 0;
}

程序运行结果如下:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值