二项队列———数据结构与算法分析第二版(C)

  • 引论

左堆的合并,插入,删除最小的时间复杂度为O(logN)。二项队列就是为了对这些结果进一步提高的一种数据结构。利用二项队列,这三种操作的最坏时间复杂度为O(logN),但是插入的平均时间复杂度为O(1)

  • 二项队列

二项队列不是一棵树,它是一个森林,由一组堆序的树组成的深林,叫做二项队列。

二项队列有几个性质比较重要

(a) 每一颗树都是一个有约束的堆序树,叫做二项树

(b) 高度为k的第k个二项树Bk由一个根节点和B0, B1, .......B(k-1)构成

(c) 高度为k的二项树的结点个数为2^k

我们可以用二项树的结合表示任意大小的优先队列。例如,大小为13的优先队列就可以用B3,B2,B0来表示,二进制的表示为1101。对此,我深表怀疑二项队列是不是受二进制的启发而产生的。

  • 二项队列的操作

查找最小项:只需要查找每个二项树的根节点就可以了,因此时间复杂度为O(logN)。

合并:通过把两个队列相加在一起完成。因为有O(logN)棵树,所以合并的时间复杂度也是O(logN)。

插入:插入也是一种合并,只不过是把插入的结点当做B0。虽然感觉插入的时间复杂度是O(logN),但是实际是O(1),因为有一定的概率是被插入的二项队列没有B0。

删除最小:在根结点找到最小值,然后把最小值所在的树单独拿出分列为二项队列,然后把这个新的二项队列与原二项队列进行合并。每一个过程的时间复杂度为O(logN)。故加起来的时间复杂度仍为O(logN)。

这些操作归根结底是合并Merge。

  • 二项队列的代码实现

(1) 二项队列声明:

 1 typedef struct BinNode *Position;
 2 typedef struct BinNode *BinTree;
 3 typedef struct Collection *BinQueue;
 4 struct BinNode
 5 {
 6     ElementType Element;
 7     Position LeftChild;
 8     Position Sibling;
 9 };
10 struct Collection
11 {
12     int CurrentSize;
13     BinTree TheTrees[MaxTree];
14 }
15  

首先定义了树BinNode,然后定义了森林Collection。

下图是TheTrees,数组里装的是指向个个二项树的指针。以及二项队列在上面定义的结构里面的表示方式。可以看出,根节点仅指向一个有最多子树的子结点,由这个结点指向各个兄弟节点,所以访问必然是逐级访问。

(2)合并树:

合并树本质是指针的变动。当然要对两个二项树做好变换。

1
2 BinTree CombineTree(BinTree T1,BinTree T2)
3 {
4     if(T1->Element>T2->Element)
5         return CombineTree(T2,T1);
6     T2->Sibling = T1->LeftChild;
7     T1->LeftChild = T2;
8     return T1;
9 }  

(3)合并两个优先队列(merge):

 1 BinQueue Merge(BinQueue H1, BinQueue H2)
 2 {
 3     BinTree T1, T2, Carry = NULL;
 4     int i,j;
 5     if(H1->CurrentSize+H2->CurrentSize>Capacity)
 6         Error("Exceed the Capacity");
 7     H1->CurrentSize = H1->CurrentSize + H2->CurrentSize;  //CurrentSize含义:
 8     for(i=0,j=1;j<H1->CurrentSize;i++,j*=2)  //j:用于中止循环条件
 9     {
10         T1 = H1->TheTrees[i];
11         T2 = H2->TheTrees[i];
12         switch(!!T1+2*!!T2+4*!!Carry)
13         {
14             case 0: //No Trees
15             case 1: //Only H1
16                 break;
17             case 2:
18                 H1->TheTrees[i] = T2;
19                 H2->TheTrees[i] = NULL;
20                 break;
21             case 4: //Only Carry
22                 H1->TheTrees[i] = Carry;
23                 Carry = NULL;
24                 break;
25             case 3: //T1,T2
26                 Carry = CombineTree(T1,T2);
27                 H1->TheTrees[i] = H2->TheTrees[i] = NULL;
28                 break;
29             case 5:
30                 Carry = CombineTree(T1,Carry);
31                 H1->TheTrees[i] = NULL;
32                 break;
33             case 6:
34                 Carry = CombineTree(T2,Carry);
35                 H2->TheTrees[i] = NULL;
36                 break;
37             case 7:
38                 H1->TheTrees[i] = Carry;
39                 Carry = CombineTree(T1,T2);
40                 H2->TheTrees[i] = NULL;
41                 break;
42         }
43     }
44     return H1;
45 }   

在这段程序中,switch语句的加法是很不错的。

还有一个问题就是:怎么控制需要几阶二项队列,这直接导致程序要循环几次的问题。这里把两个二项队列的大小相加,假设是12的话,那么应该是4阶,因为3阶的大小为1+2+4 = 9<12,故应该为四阶,这也是循环控制的方式。

1 for(i=0,j=1;j<H1->CurrentSize;i++,j*=2)  

(4)删除最小值(DeleteMin):

 1 ElementType DeleteMin(BinQueue H)
 2 {
 3     int i,j;
 4     int MinTree;
 5     BinQueue DeleteQueue;
 6     Position DeletedTree, OldRoot;
 7     ElementType MinItem;
 8
 9     if(IsEmpty(H))
10     {
11         Error("Empty BinQueue!!");
12         return -Infinity;
13     }
14     //find the minmum
15     Min = Infinity;
16     for(i=0;i<MaxTree;i++)
17     {
18         if(H->TheTrees[i] && H->TheTrees[i]->Element<MinItem)
19         {
20             // Updata the minmun
21             MiniItem = H->TheTrees[i]->Element;
22             MinTree = i;
23         }
24     }
25     // have found the DeleteTree
26     DeleteTree = H->TheTrees[MinTree];
27     OldRoot = DeleteTree;
28     DeleteTree = OldRoot->LeftChild;
29     free(OldRoot);
30
31     // form the DeleteQueue
32     DeletedQueue = Initialize();
33     DeletedQueue->CurrentSize = (1<<MinTree) - 1;  //左移Mintree位
34
35     for(j=MinTree-1;j>=0;j--)
36     {
37         DeletedQueue->TheTree[j] = DeletedTree;
38         DeletedTree = DeletedTree->Sibling;
39         DeletedQueue->TheTree[j]->Sibling = NULL;
40     }
41     H->TheTrees[MiniTree] = NULL;
42     H->CurrentSize -= DeletedQueue->CurrentSize+1;
43
44     Merge(H,DeletedQueue);
45     return MinItem;
46
47 }  

转自:http://blog.csdn.net/changyuanchn/article/details/14648463

时间: 2024-12-09 13:01:49

二项队列———数据结构与算法分析第二版(C)的相关文章

数据结构 编程实战 汇总———数据结构与算法分析第二版(C)

优先队列实现事件模拟 :http://maozj.iteye.com/blog/676567 d堆 左式堆 斜堆: http://blog.csdn.net/yangtrees/article/details/8252760 二项队列:http://www.cnblogs.com/xing901022/archive/2012/09/23/2699130.html (C++) http://blog.csdn.net/changyuanchn/article/details/14648463 (

数据结构--二项队列分析及实现

一,介绍 什么是二项队列,为什么会用到二项队列? 与二叉堆一样,二项队列也是优先级队列的一种实现方式.在 数据结构--堆的实现之深入分析 的末尾 ,简单地比较了一下二叉堆与二项队列. 对于二项队列而言,它可以弥补二叉堆的不足:merge操作的时间复杂度为O(N).二项队列的merge操作的最坏时间复杂度为O(logN). 二,二项队列的基本操作及实现 在详细介绍二项的队列的基本操作之前,先了解下二项队列这种数据结构: 1)一个二项队列是若干棵树的集合.也就是说,二项队列不仅仅是一棵树,而是多棵树

转载:数据结构 二项队列

0)引论 左堆的合并,插入,删除最小的时间复杂度为O(logN).二项队列就是为了对这些结果进一步提高的一种数据结构.利用二项队列,这三种操作的最坏时间复杂度为O(logN),但是插入的平均时间复杂度为O(1). 1)二项队列 二项队列不是一棵树,它是一个森林,由一组堆序的树组成的深林,叫做二项队列. 二项队列有几个性质比较重要 (a) 每一颗树都是一个有约束的堆序树,叫做二项树 (b) 高度为k的第k个二项树Bk由一个根节点和B0, B1, .......B(k-1)构成 (c) 高度为k的二

数据结构--二项队列的思想与实现

二项队列不是一颗堆序的树,而是堆序树的集合,称为森林,森林中每棵树都是有约束的形式,称为二项树,高度为k的第k个二项树Bk由一个根节点和B0, B1, .......B(k-1)构成,高度为k的二项树的结点个数为2^k,因此可以用二项树的结合表示任意大小的优先队列.例如,大小为13的优先队列就可以用B3,B2,B0来表示,2^0+2^2+2^3 = 13.因此二进制的表示为1101. 例如,二项树B0,B1,B2,B3表示如下: 把所有二项树的根节点按规律放在一个根节点组成的数组中,就组成二项队

优先队列——二项队列(binominal queue)

[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

优先队列(堆)&#183;二项队列

目录 一. 定义 二. 结构 三. 操作 3.1. 合并 3.1. 删除最小值(deleteMin) 四. 二项队列的实现 代码地址 一. 定义 ? 我们知道,左式堆每次操作的时间界是\(O(logN)\).二项队列支持合并.插入.删除最小值,每次插入的平均时间为常数时间,而最坏时间是\(O(logN)\). ? 二项队列: 不是一棵堆序的树,而是堆序的树的集合,成为森林. 森林的每棵树都是二项树(binomial tree). 每个高度上至多存在一棵二项树. 二. 结构 ? 结构图解: ? 高

二项队列

二项队列是 堆序 的集合,也叫 森林.其中每一种形式都有约束. 二项树Bk由一个带有儿子的B0,B1,B2...组成,高度为k的二项树 恰好有2^k个结点.每一种高度只能出现一次...因此,只有1,2,4,8...等结点数目的二项树 deleteMin操作需要快速的找出跟的所有子树的能力,因此需要一般树的表示方法: 每个结点的儿子都在一个链表中,而且每个结点都有一个指向它的第一个儿子的指针. 二项树的每一个结点包括:数据,第一个儿子,以及右兄弟 下面是二项队列类构架及结点定义: 1 templa

二项队列的查找插入合并操作

源码例如以下: /* <span style="color:#ff0000;">一棵二次幂堆</span>是一棵左有序的堆,由右子树为空左子树为全然二叉树构成的根组成 <span style="color:#ff0000;">二项队列</span>:是二次幂堆的一个集合. 当中不存在相等大小的堆.其结构由队列节点数目确定 相应整数的二进制表示. */ #include <stdlib.h> #include

学习记录:数据结构与算法分析c++版

数据结构与算法分析c++版 学习记录 一.绪论 1.数据结构的必要性 计算机程序被设计出来的目的不仅仅是为了计算,同时其也要完成数据的提取和检索任务,并尽可能地高效快速.在这个意义下,数据结构和算法分析作为程序的核心,就显得尤为重要.如何利用数据结构和算法,设计出简单易懂,并且高效地利用计算机资源的程序是这门课的核心议题. Def    一个算法被称为有效的(effective),如果其能在计算机的资源限制下解决相应问题:这些限制通常包括计算机储存量限制,以及算法运行的时间限制.    算法的消