【0】README

0.1) 本文文字描述部分转自 数据结构与算法分析, 旨在理解 优先队列——二项队列(binominal queue) 的基础知识;
0.2) 本文核心的剖析思路均为原创(insert,merge和deleteMin的操作步骤图片示例), 源代码均为原创
0.3) for original source code, please visit https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter6/p152_binominal_queue


【1】二项队列相关

1.0)Attention: 二项队列中不允许有高度相同的二项树存在该队列中;
1.1)problem+solution:

  • 1.1.1)problem:虽然左式堆和斜堆每次操作花费O(logN)时间, 这有效地支持了合并, 插入和deleteMin, 但还是有改进的余地,因为我们知道, 二叉堆以每次操作花费常数平均时间支持插入。
  • 1.1.2)solution: 二项队列支持所有这三种操作(merge + insert + deleteMin), 每次操作的最坏情形运行时间为O(logN), 而插入操作平均花费常数时间; (干货——优先队列的三种基本操作——merge + insert + deleteMin)

1.2)相关定义

  • 1.2.1) 二项队列定义: 二项队列不同于我们看到的所有优先队列的实现之处在于, 一个二项队列不是一颗堆序的树, 而是堆序树的集合,称为森林;(干货——二项队列的定义和构成,二项队列是二项树的集合,而二项树是一颗堆序树)
  • 1.2.2)二项树定义: 堆序树中的每一颗都是有约束的形式。 (干货——二项树的定义)
  • 1.2.3)二项树的构成:每一个高度上至多存在一颗二项树, 高度为0的二项树是一颗单节点树; 高度为k 的二项树Bk 通过将一颗二项树 Bk-1 附接到另一颗二项树Bk-1 的根上而构成;(干货——二项树的构成)

对上图的分析(Analysis):

  • A1)二项树的性质:

    • A1.1)从图中看到, 二项树Bk 由一个带有儿子B0, B1, …, Bk-1的根组成;
    • A1.2)高度为k 的二项树恰好有2^k 个节点;
    • A1.3) 而在深度d 的节点数是 二项系数 。
  • A2)如果我们把堆序添加到二项树上, 并允许任意高度上最多有一颗二项树,那么我们能够用二项树的集合唯一地表示任意大小的优先队列;


【2】二项队列操作(merge + insert + deleteMin)

2.1)合并操作(merge) (干货——合并操作的第一步就是查看是否有高度相同的二项树,如果有的话将它们merge)

  • step1) H1 没有高度为0的二项树而H2有,所以将H2中高度为0的二项树直接作为H3的一部分;(直接的意思==中间不需要merge);
  • step2) H1 和 H2 中都有高度为1的二项树,将它们进行merge, 得到高度为2的二项树(根为12);
  • step3)现在存在三颗高度为2的二项树(根分别为12, 14, 23),将其中两个进行merge(如merge根为12 和 根为14 的二项树),得到高度为3的二项树;
  • step4)所以,最后,我们得到二项队列, 其集合包括:高度为0的二项树(根为13), 高度为1的二项树(根为23),高度为3的二项树(高度为12);

Attention)

  • A1)显然,merge操作是按照高度升序依次进行的;
  • A2)最后得到的二项队列不存在高度相同的二项树,即使存在,也要将高度相同的二项树进行merge;
  • A3)二项队里中的二项树的高度不必囊括所有的升序实数,即不必一定是0, 1, 2, 3,4 等等; 也可以是0, 1, 3 等;
  • A4)单节点树的高度为0; (干货——树高度从零起跳)

2.2)插入操作(insert) (干货——insert操作是merge操作的特例,而merge操作的第一步就是查看是否有高度相同的二项树,如果有的话将它们merge)

  • 2.2.1)插入操作实际上: 就是特殊情形的合并, 我们只需要创建一颗单节点树并执行一次merge;
  • 2.2.2)更准确地说: 如果元素将要插入的那个优先队列中不存在的最小的二项树是Bi, 那么运行时间与 i + 1 成正比;

对上图的分析(Analysis):

  • A1) 4 插入之后,与B0(根为3)进行merge, 得到一颗高度为1的树B1’(根为3);
  • A2)将B1’ 与 B1(根为1) 进行merge 得到高度为2 的树B2’(根为1), 它是新的优先队列;
  • A3)在插入7之后的下一次插入又是一个坏情形, 因为需要三次merge操作;

2.3)删除最小值操作(deleteMin)

  • step1)找出一颗具有最小根的二项树来完成, 令该树为Bk, 令原始序列为H;
  • step2)从H中除去Bk, 形成新的二项队列H’;
  • step3)再除去Bk的根, 得到一些二项树B0, B1, …, Bk-1, 它们共同形成优先队列H”;
  • step4) 合并H’ 和 H” , 操作结束;

【3】 source code and printing results

3.1)source code at a glance
Attention)二项队列的实现源代码用到了 儿子兄弟表示法

#include "binominal_queue.h" #define MINIMAL 10000int minimal(BinominalQueue bq)
{int capacity;int i;int minimal;int miniIndex;  minimal = MINIMAL;capacity = bq->capacity;for(i=0; i<capacity; i++){if(bq->trees[i] && bq->trees[i]->value < minimal){minimal = bq->trees[i]->value;miniIndex = i;}}return miniIndex;
}// initialize the BinominalQueue with given capacity.
BinominalQueue init(int capacity)
{BinominalQueue queue;           BinominalTree* trees; int i;queue = (BinominalQueue)malloc(sizeof(struct BinominalQueue));if(!queue){Error("failed init, for out of space !");return queue;}   queue->capacity = capacity;trees = (BinominalTree*)malloc(capacity * sizeof(BinominalTree));if(!trees){Error("failed init, for out of space !");return NULL;}   queue->trees = trees;for(i=0; i<capacity; i++){queue->trees[i] = NULL;}return queue;
}  // attention: the root must be the left child of the binominal tree.
int getHeight(BinominalTree root)
{int height;     if(root == NULL){       return 0;       }height = 1; while(root->nextSibling){height++;root = root->nextSibling;}return height;
}// merge BinominalQueue bq2 into bq1.
void outerMerge(BinominalQueue bq1, BinominalQueue bq2)
{int height;int i;for(i=0; i<bq2->capacity; i++){height = -1;if(bq2->trees[i]){height = getHeight(bq2->trees[i]->leftChild);   // attention for the line above// height = height(bq2->trees[i]->leftChild); not height = height(bq2->trees[i]);merge(bq2->trees[i], height, bq1);}                   }
}// merge tree h1 and h2 = bq->trees[height],
// who represents the new tree and old one respectively.
BinominalTree merge(BinominalTree h1, int height, BinominalQueue bq)
{           if(h1 == NULL){return h1;}if(bq->trees[height] == NULL) // if the queue don't has the B0 tree.{       bq->trees[height] = h1;return bq->trees[height];}else // otherwise, compare the new tree's height with that of old one.{        if(h1->value > bq->trees[height]->value) // the new should be treated as the parent of the old.{       innerMerge(bq->trees[height], height, h1, bq);}else // the old should be treated as the parent of the new.{innerMerge(h1, height, bq->trees[height], bq);}}  return h1;
} BinominalTree lastChild(BinominalTree root)
{               while(root->nextSibling){       root = root->nextSibling;}return root;
}// merge tree h1 and h2 = bq->trees[height],
// who represents the new tree and old one respectively.
BinominalTree innerMerge(BinominalTree h1, int height, BinominalTree h2, BinominalQueue bq)
{if(h1->leftChild == NULL){h1->leftChild = h2;}else{lastChild(h1->leftChild)->nextSibling = h2;// attention for the line above// lastChild(h1->leftChild)->nextSibling = h2 not lastChild(h1)->nextSibling = h2}height++;bq->trees[height-1] = NULL;merge(h1, height, bq);  return h1;
} // insert an element with value into the priority queue.
void insert(ElementType value, BinominalQueue bq)
{TreeNode node;node = (TreeNode)malloc(sizeof(struct TreeNode));if(!node){Error("failed inserting, for out of space !");return ;}node->leftChild= NULL;node->nextSibling = NULL;   node->value = value;    merge(node, 0, bq);
}// analog print node values in the binominal tree, which involves preorder traversal.
void printPreorderChildSibling(int depth, BinominalTree root)
{           int i;if(root) {      for(i = 0; i < depth; i++)printf("    ");printf("%d\n", root->value);            printPreorderChildSibling(depth + 1, root->leftChild);                                  printPreorderChildSibling(depth, root->nextSibling);} else{for(i = 0; i < depth; i++)printf("    ");printf("NULL\n");}
}// print Binominal Queue bq
void printBinominalQueue(BinominalQueue bq)
{int i;for(i=0; i<bq->capacity; i++){printf("bq[%d] = \n", i);printPreorderChildSibling(1, bq->trees[i]);}
}void deleteMin(BinominalQueue bq)
{int i;  BinominalTree minitree; BinominalTree sibling;i = minimal(bq);minitree = bq->trees[i]->leftChild; //minitree->value=51free(bq->trees[i]);bq->trees[i] = NULL;            while(minitree){sibling = minitree->nextSibling;minitree->nextSibling = NULL;merge(minitree, getHeight(minitree->leftChild), bq);        minitree = sibling;}
}

3.2) printing results

优先队列——二项队列(binominal queue)相关推荐

  1. 【数据结构与算法】二项队列的Java实现

    引言 优先队列支持三种高效实现: 二叉堆 左式堆 二项队列 二项队列是二叉堆.左式堆以外,优先队列的另外一种支持高效合并操作的实现. 二叉堆和左式堆不论怎么说,逻辑结构都算是二叉树:但二项队列不是二叉 ...

  2. 【数据结构与算法】二项队列与二叉堆的比较

    导语 二叉堆确实是入门级的重要数据结构了,而二项队列也是慢慢要去掌握的一种支持高效合并的优先队列实现.本文稍作比较,望抛砖引玉. 列个表格比较基本操作性能 基本操作 insert(平均) delete ...

  3. 堆之二项堆(Binominal Heap)

    二叉堆/二项堆/斐波那契堆 二叉堆/二项堆/斐波那契堆_m0_37683758的博客-CSDN博客_二项堆 二项堆 二项堆_alike_meng的博客-CSDN博客 堆之二项堆 堆之二项堆_跨世纪逃兵 ...

  4. 可合并堆1:二项堆(Binominal Heap)

    二项堆是一种可合并队,其合并的复杂度为.二项堆与二项树有着天然的联系,解析二项堆之前,先解析二项树. 1k阶二项树是一个递归定义: (1)单个节点是一颗二项树,表示为 (2)二项树由两颗二项树组成 ( ...

  5. NVMe系列专题之二:队列(Queue)管理

    转载链接:https://mp.weixin.qq.com/s?__biz=MzIwNTUxNDgwNg==&mid=2247484355&idx=1&sn=04f0617bf ...

  6. 栈(Stack)与队列(Queue)

    定义 栈:后进先出(LIFO-last in first out):最后插入的元素最先出来. 队列:先进先出(FIFO-first in first out):最先插入的元素最先出来. 图示 在这里插 ...

  7. python循环队列_JS 队列-优先队列、循环队列

    <学习JavaScript数据结构与算法>读书笔记. 队列是遵行FIFO(First In First Out, 先进先出)原则的一组有序的项.队列再尾部添加新元素,并从顶部移除元素. 在 ...

  8. [译] 流量控制(TC)五十年:从基于缓冲队列(Queue)到基于时间戳(EDT)的演进...

    译者序 本文组合翻译了 Google 2018 年两篇分享中的技术部分,二者讲地同一件事情,但层次侧重不同: Netdev 2018: Evolving from AFAP: Teaching NIC ...

  9. 数据结构:栈和队列(Stack Queue)【详解】

    友情链接:数据结构专栏 目录 栈和队列 [知识框架] 栈 一.栈的基本概念 1.栈的定义 2.栈的常见基本操作 二.栈的顺序存储结构 1.栈的顺序存储 2.顺序栈的基本算法 (1)初始化 (2)判栈空 ...

最新文章

  1. mysql实现gb18030转utf8_将编码是GB18030的小文件转为UTF8
  2. 【Android APT】注解处理器 ( 注解标注 与 初始化方法 )
  3. 博士生传给硕士生的经验
  4. kmeans 是Nondeterministic algorithm
  5. Java 中的 Reference
  6. 哈佛大学教授:排名前5%学生的秘诀就3个字,这比勤奋更重要!
  7. [svn] 解决SVN冲突攻略(手册)
  8. 清华孵化、张钹加盟、天使估值5个亿,创业半年的RealAI什么来头?
  9. c++ 传智课件_沪科版初中物理九年级全册第二节 科学探究:物质的比热容公开课优质课课件教案视频...
  10. 分寸:切记别把话说得太死 — 《别输在不会表达上》
  11. 例4.2 又一版A+B - 九度教程第43题(进制转换)
  12. sqlServer2005升级到sqlServer2008R2
  13. Tomcat的JDBC连接池
  14. 78 python - 打飞机案例(让敌机移动)
  15. APS生产计划排产在装备制造业的应用
  16. js date日期格式化
  17. 编写python爬虫基础_0基础如何快速写python爬虫
  18. 网络与信息安全-第三章-对称秘钥加密算法
  19. 1124 Raffle for Weibo Followers(map)
  20. win7(主机)+win7虚拟机(vmware,被调试机)+windbg配置内核驱动调试

热门文章

  1. 二项式反演(非详细)
  2. 【HDU-2376】Average distance
  3. 牛客题霸 [ 换钱的最少货币数] C++题解/答案
  4. 天下第一 txdy (LCT+双指针+线段树)
  5. 数论三之排列组合Ⅱ——Virus Tree 2,RGB Coloring,123 Triangle,排列计数,排队,卡农
  6. codeforces1498 D. Bananas in a Microwave(背包+优化)
  7. CF1120D Power Tree(树形DP/构造+差分+最小生成树)
  8. Juice Extractor dp
  9. Spring Cloud面试题(2020最新版)
  10. springboot 多数据源mybatis的两种整合方法