#include <stdio.h>
#include<stdlib.h> //二项队列支持合并,插入,删除最小值等操作,且每次操作最坏花费log N
//二项队列不是一个堆序,而是一群堆序的集合
#define Infinity 10000
#define MaxTrees 14 //Capacity size 2^14 - 1
#define Capacity 16383
typedef int ElementType;
typedef struct BinNode *Position; //二项树节点
typedef struct BinNode *BinTree;
typedef struct Collection *BinQueue; // 二项队列
BinTree CombineTrees(BinTree T1,BinTree T2); //合并二项树
BinQueue Merge(BinQueue H1,BinQueue H2); //合并二项队列,二项队列即森林,二项树的集合
ElementType DeleteMin(BinQueue H); //删除二项队列中最小值
int IsEmpty(BinQueue H); //判空
int IsFull( BinQueue H ); //判满
BinQueue Initialize(void); //初始化二项队列
static void DestroyTree( BinTree T ); //销毁二项树
void Destroy( BinQueue H ); //销毁二项队列
BinQueue MakeEmpty( BinQueue H ); //清空二项队列
ElementType FindMin( BinQueue H ); //找到二项队列中最小值
BinQueue Insert( ElementType Item, BinQueue H ); //插入
int main(void)
{
BinQueue H;
H = Initialize();
H = Insert(44,H);
H = Insert(46,H);
printf("%d",FindMin(H));
printf("\nHello World!\n");
return 0;
}
struct BinNode //二项树节点
{
ElementType Element;
Position LeftChild;
Position NextSibling;
};
struct Collection //二项队列
{
int CurrentSize;
BinTree TheTrees[MaxTrees]; //二项队列的长度为MaxTrees
};
BinTree CombineTrees(BinTree T1,BinTree T2) //合并T1,T2两个二项树
{
if(T1->Element > T2->Element)
return CombineTrees(T2,T1); //当T1的值小于T2的值时
T2->NextSibling = T1->LeftChild; //T1的右兄弟指向T2的左儿子,刚开始T1的右兄弟指向无意义点
T1->LeftChild = T2; //T1的左儿子指向T2
return T1;
}
BinQueue Merge(BinQueue H1,BinQueue H2) //合并两个二项队列
{
BinTree T1,T2,Carry = NULL; //Carry 存放上一步得来的树,可能是NULL
int i,j;
if(H1->CurrentSize + H2->CurrentSize >Capacity)
printf("Merge Would Excead Capacity\n");
H1->CurrentSize += H2->CurrentSize; //H1的当前大小为H1 加上 H2
for( i = 0,j = 1; j <= H1->CurrentSize;i++,j *= 2 ) //利用j是因为当前H1的大小已经加上了H2 的大小
{ //因为二项队列中元素 按2 4 8 16 32 递增所以*2
T1 = H1->TheTrees[i];
T2 = H2->TheTrees[i];
switch (!!T1 + 2 * !!T2 + 4 * !!Carry) // !! 两个逻辑运算符,只有 1 or 0 两种结果
{ //例 !!2 = 1, !!5 = 1,!!0 = 0
case 0: //NO tree
case 1: //only H1
break;
case 2: //only H2
H1->TheTrees[i] = T2;
H2->TheTrees[i] = NULL;
break;
case 4: //only Carry*
H1->TheTrees[i] = Carry;
Carry = NULL;
break;
case 3: //H1 and H2
Carry = CombineTrees(T1,T2);
H1->TheTrees[i] = H2->TheTrees[i] = NULL;
break;
case 5: //H1 and Carry*
Carry = CombineTrees(T1,Carry);
H1->TheTrees[i] = NULL;
break;
case 6: //H2 and Carry*
Carry = CombineTrees(T2,Carry);
H2->TheTrees[i] = NULL;
break;
case 7: // all trees
H1->TheTrees[i] = Carry;
Carry = CombineTrees(T1,T2);
H2->TheTrees[i] = NULL;
break;
}
}
// free(H2);
return H1;
}
ElementType DeleteMin(BinQueue H) //删除最小值
{
int i,j;
int MinTree;
BinQueue DeletedQueue;
Position DeletedTree,OldRoot;
ElementType MinItem;
if(IsEmpty(H))
{
printf("Empty Binomial Queue\n");
return -Infinity;
}
MinItem = Infinity;
for( i = 0; i < MaxTrees;i++) //遍历整个二项队列,找到具有最小值的二项树
{
if(H->TheTrees[i] &&
H->TheTrees[i]->Element < MinItem)
{
MinItem = H->TheTrees[i]->Element; //最小值为 MinItem
MinTree = i; //具有最小值的二项树为H->TheTrees[Mintree]
}
}
DeletedTree = H->TheTrees[MinTree]; //DeletedTree and OldRoot 设为具有最小值的二项队列
OldRoot = DeletedTree;
DeletedTree = DeletedTree->LeftChild; //保留最小二项树中最小节点的左孩子,右兄弟为NULL
free(OldRoot); //删除最小二项树中最小值的节点
DeletedQueue = Initialize(); //初始化一个二项队列DeletedQueue
//初始化该二项队列的大小为,因为删除了头节点,所以-1
DeletedQueue->CurrentSize = (1 << MinTree) - 1;
for( j = MinTree - 1; j >= 0 ; j-- ) //从该二项树前一个开始
{ //将这个二项树分解为一个二项队列
DeletedQueue->TheTrees[j] = DeletedTree;
DeletedTree = DeletedTree->NextSibling;
DeletedQueue->TheTrees[j]->NextSibling = NULL; //二项队列的二项树的第一个右兄弟为NULL
}
H->TheTrees[MinTree] = NULL;
H->CurrentSize -= DeletedQueue->CurrentSize + 1; //减去DeletedQueue->Cur 是因为下一步合并是要加上
Merge(H,DeletedQueue); //合并
return MinItem; //返回删除的最小值
}
int IsEmpty( BinQueue H ) //判空
{
return H->CurrentSize == 0; //判断当前大小是否等于0
}
int IsFull( BinQueue H ) //判满
{ //判断当前大小是否等于最大值
return H->CurrentSize == Capacity;
}
BinQueue Initialize(void) //初始化
{
BinQueue H;
int i;
H = (BinQueue)malloc(sizeof(struct Collection)); //为二项队列分配空间,包括其中二项树的空间
if(NULL == H)
printf("Out Of Space\n");
H->CurrentSize = 0; //当前大小为0
for( i = 0; i < MaxTrees; i++ )
H->TheTrees[ i ] = NULL; //每个二项树初始指向NULL
return H;
}
static void DestroyTree( BinTree T ) //删除二项树
{
if( T != NULL )
{
DestroyTree( T->LeftChild ); //递归删除二项树的左儿子
DestroyTree( T->NextSibling ); //递归删除二项树的右兄弟
free( T ); //删除该节点 or 二项树
}
}
void Destroy( BinQueue H ) //删除二项队列,但不删除头节点 H
{
int i;
for( i = 0; i < MaxTrees; i++ )
DestroyTree( H->TheTrees[ i ] ); //从头开始一个个删除二项树
}
BinQueue MakeEmpty( BinQueue H ) //清空二项队列
{
int i;
Destroy( H ); //
for( i = 0; i < MaxTrees; i++ )
H->TheTrees[ i ] = NULL;
H->CurrentSize = 0;
return H;
}
ElementType FindMin( BinQueue H ) //返回最小值
{
int i;
ElementType MinItem;
if( IsEmpty( H ) )
{
printf("Empty binomial queue");
return 0;
}
MinItem = Infinity; //初始化最小值
for( i = 0; i < MaxTrees; i++ )
{
if( H->TheTrees[ i ] &&
H->TheTrees[ i ]->Element < MinItem )
MinItem = H->TheTrees[ i ]->Element; //从头开始一个个找最小值
}
return MinItem;
}
BinQueue Insert( ElementType Item, BinQueue H ) //插入一个数
{
BinTree NewNode;
BinQueue OneItem;
NewNode =(BinTree)malloc( sizeof( struct BinNode ) ); //分配一个树节点
if( NewNode == NULL )
printf("Out Of Space\n");
NewNode->LeftChild = NewNode->NextSibling = NULL;
NewNode->Element = Item;
OneItem = Initialize(); //初始化一个二项队列
OneItem->CurrentSize = 1; //二项队列的大小为 1,即二项队列中二项树节点数
OneItem->TheTrees[ 0 ] = NewNode; //该二项队列只有一个二项树 NewNode
return Merge( H, OneItem ); //合并 H 和该二项队列
}
#include<stdlib.h> //二项队列支持合并,插入,删除最小值等操作,且每次操作最坏花费log N
//二项队列不是一个堆序,而是一群堆序的集合
#define Infinity 10000
#define MaxTrees 14 //Capacity size 2^14 - 1
#define Capacity 16383
typedef int ElementType;
typedef struct BinNode *Position; //二项树节点
typedef struct BinNode *BinTree;
typedef struct Collection *BinQueue; // 二项队列
BinTree CombineTrees(BinTree T1,BinTree T2); //合并二项树
BinQueue Merge(BinQueue H1,BinQueue H2); //合并二项队列,二项队列即森林,二项树的集合
ElementType DeleteMin(BinQueue H); //删除二项队列中最小值
int IsEmpty(BinQueue H); //判空
int IsFull( BinQueue H ); //判满
BinQueue Initialize(void); //初始化二项队列
static void DestroyTree( BinTree T ); //销毁二项树
void Destroy( BinQueue H ); //销毁二项队列
BinQueue MakeEmpty( BinQueue H ); //清空二项队列
ElementType FindMin( BinQueue H ); //找到二项队列中最小值
BinQueue Insert( ElementType Item, BinQueue H ); //插入
int main(void)
{
BinQueue H;
H = Initialize();
H = Insert(44,H);
H = Insert(46,H);
printf("%d",FindMin(H));
printf("\nHello World!\n");
return 0;
}
struct BinNode //二项树节点
{
ElementType Element;
Position LeftChild;
Position NextSibling;
};
struct Collection //二项队列
{
int CurrentSize;
BinTree TheTrees[MaxTrees]; //二项队列的长度为MaxTrees
};
BinTree CombineTrees(BinTree T1,BinTree T2) //合并T1,T2两个二项树
{
if(T1->Element > T2->Element)
return CombineTrees(T2,T1); //当T1的值小于T2的值时
T2->NextSibling = T1->LeftChild; //T1的右兄弟指向T2的左儿子,刚开始T1的右兄弟指向无意义点
T1->LeftChild = T2; //T1的左儿子指向T2
return T1;
}
BinQueue Merge(BinQueue H1,BinQueue H2) //合并两个二项队列
{
BinTree T1,T2,Carry = NULL; //Carry 存放上一步得来的树,可能是NULL
int i,j;
if(H1->CurrentSize + H2->CurrentSize >Capacity)
printf("Merge Would Excead Capacity\n");
H1->CurrentSize += H2->CurrentSize; //H1的当前大小为H1 加上 H2
for( i = 0,j = 1; j <= H1->CurrentSize;i++,j *= 2 ) //利用j是因为当前H1的大小已经加上了H2 的大小
{ //因为二项队列中元素 按2 4 8 16 32 递增所以*2
T1 = H1->TheTrees[i];
T2 = H2->TheTrees[i];
switch (!!T1 + 2 * !!T2 + 4 * !!Carry) // !! 两个逻辑运算符,只有 1 or 0 两种结果
{ //例 !!2 = 1, !!5 = 1,!!0 = 0
case 0: //NO tree
case 1: //only H1
break;
case 2: //only H2
H1->TheTrees[i] = T2;
H2->TheTrees[i] = NULL;
break;
case 4: //only Carry*
H1->TheTrees[i] = Carry;
Carry = NULL;
break;
case 3: //H1 and H2
Carry = CombineTrees(T1,T2);
H1->TheTrees[i] = H2->TheTrees[i] = NULL;
break;
case 5: //H1 and Carry*
Carry = CombineTrees(T1,Carry);
H1->TheTrees[i] = NULL;
break;
case 6: //H2 and Carry*
Carry = CombineTrees(T2,Carry);
H2->TheTrees[i] = NULL;
break;
case 7: // all trees
H1->TheTrees[i] = Carry;
Carry = CombineTrees(T1,T2);
H2->TheTrees[i] = NULL;
break;
}
}
// free(H2);
return H1;
}
ElementType DeleteMin(BinQueue H) //删除最小值
{
int i,j;
int MinTree;
BinQueue DeletedQueue;
Position DeletedTree,OldRoot;
ElementType MinItem;
if(IsEmpty(H))
{
printf("Empty Binomial Queue\n");
return -Infinity;
}
MinItem = Infinity;
for( i = 0; i < MaxTrees;i++) //遍历整个二项队列,找到具有最小值的二项树
{
if(H->TheTrees[i] &&
H->TheTrees[i]->Element < MinItem)
{
MinItem = H->TheTrees[i]->Element; //最小值为 MinItem
MinTree = i; //具有最小值的二项树为H->TheTrees[Mintree]
}
}
DeletedTree = H->TheTrees[MinTree]; //DeletedTree and OldRoot 设为具有最小值的二项队列
OldRoot = DeletedTree;
DeletedTree = DeletedTree->LeftChild; //保留最小二项树中最小节点的左孩子,右兄弟为NULL
free(OldRoot); //删除最小二项树中最小值的节点
DeletedQueue = Initialize(); //初始化一个二项队列DeletedQueue
//初始化该二项队列的大小为,因为删除了头节点,所以-1
DeletedQueue->CurrentSize = (1 << MinTree) - 1;
for( j = MinTree - 1; j >= 0 ; j-- ) //从该二项树前一个开始
{ //将这个二项树分解为一个二项队列
DeletedQueue->TheTrees[j] = DeletedTree;
DeletedTree = DeletedTree->NextSibling;
DeletedQueue->TheTrees[j]->NextSibling = NULL; //二项队列的二项树的第一个右兄弟为NULL
}
H->TheTrees[MinTree] = NULL;
H->CurrentSize -= DeletedQueue->CurrentSize + 1; //减去DeletedQueue->Cur 是因为下一步合并是要加上
Merge(H,DeletedQueue); //合并
return MinItem; //返回删除的最小值
}
int IsEmpty( BinQueue H ) //判空
{
return H->CurrentSize == 0; //判断当前大小是否等于0
}
int IsFull( BinQueue H ) //判满
{ //判断当前大小是否等于最大值
return H->CurrentSize == Capacity;
}
BinQueue Initialize(void) //初始化
{
BinQueue H;
int i;
H = (BinQueue)malloc(sizeof(struct Collection)); //为二项队列分配空间,包括其中二项树的空间
if(NULL == H)
printf("Out Of Space\n");
H->CurrentSize = 0; //当前大小为0
for( i = 0; i < MaxTrees; i++ )
H->TheTrees[ i ] = NULL; //每个二项树初始指向NULL
return H;
}
static void DestroyTree( BinTree T ) //删除二项树
{
if( T != NULL )
{
DestroyTree( T->LeftChild ); //递归删除二项树的左儿子
DestroyTree( T->NextSibling ); //递归删除二项树的右兄弟
free( T ); //删除该节点 or 二项树
}
}
void Destroy( BinQueue H ) //删除二项队列,但不删除头节点 H
{
int i;
for( i = 0; i < MaxTrees; i++ )
DestroyTree( H->TheTrees[ i ] ); //从头开始一个个删除二项树
}
BinQueue MakeEmpty( BinQueue H ) //清空二项队列
{
int i;
Destroy( H ); //
for( i = 0; i < MaxTrees; i++ )
H->TheTrees[ i ] = NULL;
H->CurrentSize = 0;
return H;
}
ElementType FindMin( BinQueue H ) //返回最小值
{
int i;
ElementType MinItem;
if( IsEmpty( H ) )
{
printf("Empty binomial queue");
return 0;
}
MinItem = Infinity; //初始化最小值
for( i = 0; i < MaxTrees; i++ )
{
if( H->TheTrees[ i ] &&
H->TheTrees[ i ]->Element < MinItem )
MinItem = H->TheTrees[ i ]->Element; //从头开始一个个找最小值
}
return MinItem;
}
BinQueue Insert( ElementType Item, BinQueue H ) //插入一个数
{
BinTree NewNode;
BinQueue OneItem;
NewNode =(BinTree)malloc( sizeof( struct BinNode ) ); //分配一个树节点
if( NewNode == NULL )
printf("Out Of Space\n");
NewNode->LeftChild = NewNode->NextSibling = NULL;
NewNode->Element = Item;
OneItem = Initialize(); //初始化一个二项队列
OneItem->CurrentSize = 1; //二项队列的大小为 1,即二项队列中二项树节点数
OneItem->TheTrees[ 0 ] = NewNode; //该二项队列只有一个二项树 NewNode
return Merge( H, OneItem ); //合并 H 和该二项队列
}