欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一种二项队列实现

程序员文章站 2022-03-12 23:03:55
...

二项队列的优势:不仅支持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;
}

程序运行结果如下:

一种二项队列实现