二项队列分析及实现
来源:互联网 发布:dwg是什么软件 编辑:程序博客网 时间:2024/05/01 06:06
定义:
二项队列不同于左式堆和二叉堆等优先队列的实现之处在于,一个二项队列不是一棵堆序的树,而是堆序树的集合,即森林。堆序树中的每棵树都是由约束形式的,叫做二项树。每一个高度上至多存在一棵二项树。高度为0的二项树是一颗单节点树,高度为k的二项树Bk通过将一棵二项树Bk-1附接到另一颗二项树Bk-1的根上而构成。下图显示二项树B0,B1,B2,B3以及B4。
二项队列的复杂度
左堆的合并,插入,删除最小的时间复杂度为O(logN)。二项队列就是为了对这些结果进一步提高的一种数据结构。利用二项队列,这三种操作的最坏时间复杂度为O(logN),但是插入的平均时间复杂度为O(1)。
基本操作:
合并:
二项队列的合并操作可以看做一个简单的二进制加法运算,从低位运算到高位。首先是两个队列的B0相加,如果两个队列都存在B0(二进制为1),因此将两个B0合并成一个B1树,生成的B1树当做进位,参与下一步的B1运算,直到运算到最高位结束。
删除最小值/最大值:
删除最小值首先要做的事情就是找到最小值。那么只要寻找二项队列对应的每一刻Bk树的根节点中的最小值即可。然后把拥有最小值的Bk树删去根节点。此时剩下的树为B0,B1...Bk-1树。这些树构成一个新的二项队列,然后调用上述的合并操作,既可以完成删除操作。
插入:
插入操作等同于合并操作,非常好完成。
编码实现:
二项队列定义:
在对二项队列编码之前,需要明白如何表示二项队列。因为二项队列的根节点所指向的节点可能是无限的,所以不能像二叉树那样使用两个指针来指向两个儿子(这里有无数个儿子)。
具体的表示方式如下图所示:
第一张图代表我们画出来的二项队列。
第二张图上半部分的数组是指向树节点的指针,即指向Bk的根节点。
每个树节点有三个元素,Element,Leftchild, NextSibling。
其中NextSibling指的是和它本身同级的兄弟。如第一张图中的B3,
12没有同级兄弟,21,24,23互为同级兄弟,65,51,24互为同级兄弟。
那么Leftchild元素指向谁呢,当然是指向有最多孩子的节点,提取出来就是B2的23节点了。
理解了这里,在看第二张图想必会明白多了。
合并:合并操作的主要内容就是做二进制加法运算,使用switch来进行判断。具体到两个Bk树的合并非常的简单,如下图所示:
然较小的根节点变成新的根,另一个Bk成为它的左孩子,它原来的左孩子成为另一个Bk根节点的兄弟。
详细代码:
头文件:
- typedef long ElementType;
-
- #define Infinity (30000L)
- #ifndef _BinHeap_H
- #define _BinHeap_H
-
- #define MaxTrees (14) //二项队列中的二项树高度最大为13;
- #define Capacity (16383) //高度0,1,2,3,...,13的二项树节点数目之和
-
- struct BinNode;
- typedef struct BinNode *BinTree;
- struct Collection;
- typedef struct Collection *BinQueue;
-
- BinQueue Initialize(void);
- void Destroy( BinQueue H);
- BinQueue MakeEmpty(BinQueue H);
- BinQueue Insert(ElementType Item, BinQueue H);
- ElementType DeleteMin(BinQueue H);
- BinTree CombineTrees( BinTree T1, BinTree T2 );
- BinQueue Merge(BinQueue H1, BinQueue H2);
- ElementType FindMin(BinQueue H);
- int IsEmpty(BinQueue H);
- int IsFull(BinQueue H);
- #endif
源文件:- #include "binomial.h"
- #include <stdio.h>
- #include <stdlib.h>
-
- typedef struct BinNode *Position;
-
- struct BinNode
- {
- ElementType Element;
- Position LeftChild;
- Position NextSibling;
- };
-
- struct Collection
- {
- int CurrentSize;
- BinTree TheTrees[MaxTrees];
- };
-
- BinQueue Initialize()
- {
- BinQueue H;
- int i = 0;
- H = malloc(sizeof(struct Collection));
- if (H == NULL){
- printf("Out of space!!\n");
- return NULL;
- }
- H->CurrentSize = 0;
- for (i = 0; i < MaxTrees; ++i){
- H->TheTrees[i] = NULL;
- }
- return H;
- }
-
- static void DestroyTree(BinTree T)
- {
-
- if (T != NULL){
- DestroyTree(T->LeftChild);
- DestroyTree(T->NextSibling);
- free(T);
- }
- }
-
- void Destroy(BinQueue H)
- {
-
- int i = 0;
- for (i = 0; i < MaxTrees; ++i){
- DestroyTree(H->TheTrees[i]);
- }
- }
-
- BinQueue MakeEmpty(BinQueue H)
- {
- int i = 0;
- Destroy(H);
- for (i = 0; i < MaxTrees; ++i){
- H->TheTrees[i] = NULL;
- }
- H->CurrentSize = 0;
- return H;
- }
-
- BinQueue Insert(ElementType Item, BinQueue H)
- {
- BinTree NewNode;
- BinQueue OneItem;
- NewNode = malloc(sizeof(struct BinNode));
- if (NewNode == NULL){
- printf("Out of space!\n");
- return H;
- }
- NewNode->Element = Item;
- NewNode->LeftChild = NewNode->NextSibling = NULL;
- OneItem = Initialize();
- OneItem->CurrentSize = 1;
- OneItem->TheTrees[0] = NewNode;
- return Merge(H, OneItem);
- }
-
- ElementType FindMin(BinQueue H)
- {
- int i = 0;
- ElementType MinItem;
- if (IsEmpty(H)){
- printf("Empty binomial queue");
- return -1;
- }
- MinItem = Infinity;
-
- for (i = 0; i < MaxTrees; ++i){
- if (H->TheTrees[i] && H->TheTrees[i]->Element < MinItem){
- MinItem = H->TheTrees[i]->Element;
- }
- }
- return MinItem;
- }
-
- int IsEmpty(BinQueue H)
- {
- return H->CurrentSize == 0;
- }
-
- int IsFull(BinQueue H)
- {
- return H->CurrentSize == Capacity;
- }
-
- BinTree CombineTrees( BinTree T1, BinTree T2 )
- {
-
- if (T1 == NULL)
- return T2;
- else if (T2 == NULL)
- return T1;
- if (T1->Element > T2->Element)
- return CombineTrees(T2, T1);
-
- T2->NextSibling = T1->LeftChild;
- T1->LeftChild = T2;
- return T1;
- }
-
- BinQueue Merge(BinQueue H1, BinQueue H2)
- {
- BinTree T1, T2, Carry = NULL;
- int i = 0, j = 0;
-
- if (H1->CurrentSize + H2->CurrentSize > Capacity){
- printf("Merge would exceed capacity!\n");
- return H1;
- }
- H1->CurrentSize += H2->CurrentSize;
-
- for (i = 0, j = 1; j <= H1->CurrentSize; ++i, j *= 2){
- T1 = H1->TheTrees[i];
- T2 = H2->TheTrees[i];
-
- switch(!!T1 + 2* (!!T2) + 4 * (!!Carry)){
- case 0:
- case 1:
- break;
- case 2:
-
- H1->TheTrees[i] = T2;
- H2->TheTrees[i] = NULL;
- break;
- case 3:
-
- Carry = CombineTrees(T1, T2);
- H1->TheTrees[i] = NULL;
- H2->TheTrees[i] = NULL;
- break;
- case 4:
-
- H1->TheTrees[i] = Carry;
- Carry = NULL;
- break;
- case 5:
- Carry = CombineTrees(T1, Carry);
- H1->TheTrees[i] = NULL;
- break;
- case 6:
- Carry = CombineTrees(T2, Carry);
- H2->TheTrees[i] = NULL;
- break;
- case 7:
- H1->TheTrees[i] = Carry;
- Carry = CombineTrees(T1, T2);
- H2->TheTrees[i] = NULL;
- break;
- }
- }
- return H1;
- }
-
- ElementType DeleteMin(BinQueue H)
- {
- int i = 0, j = 0;
- int MinTree;
- BinQueue DeletedQueue;
- Position DeletedTree, OldRoot;
- ElementType MinItem;
-
- if (IsEmpty(H)){
- printf("Empty binomial queue!\n");
- return -1;
- }
-
- MinItem = Infinity;
-
- for (i = 0; i < MaxTrees; ++i){
- if (H->TheTrees[i] && H->TheTrees[i]->Element < MinItem){
- MinItem = H->TheTrees[i]->Element;
- MinTree = i;
- }
- }
-
- DeletedTree = H->TheTrees[MinTree];
- OldRoot = DeletedTree;
- DeletedTree = DeletedTree->LeftChild;
- free(OldRoot);
- DeletedQueue = Initialize();
-
-
-
- DeletedQueue->CurrentSize = (1 << MinTree) -1;
-
-
- for (j = MinTree - 1; j >= 0; --j){
- DeletedQueue->TheTrees[j] = DeletedTree;
- DeletedTree = DeletedTree->NextSibling;
- DeletedQueue->TheTrees[j]->NextSibling = NULL;
- }
-
- H->TheTrees[MinTree] = NULL;
- H->CurrentSize -= DeletedQueue->CurrentSize + 1;
- Merge(H, DeletedQueue);
- return MinItem;
- }
0 0