一種二項隊列實現

二項隊列的優勢:不僅支持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;
}

程序運行結果如下:



發佈了36 篇原創文章 · 獲贊 11 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章