太晚了,不想码字,其实这个思想真的很精妙,对于数字的应用,逻辑思路真的很巧妙清晰,如果有时间真的可以看看(数据结构与算法分析)这本书的二项队列的思路讲解,但是我的代码已经写的很清晰了,对于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;
}