可合并堆1:二项堆(Binominal Heap)
作者:互联网
二项堆是一种可合并队,其合并的复杂度为。二项堆与二项树有着天然的联系,解析二项堆之前,先解析二项树。
1k阶二项树是一个递归定义:
(1)单个节点是一颗二项树,表示为
(2)二项树由两颗二项树组成
(3)像最小二项树一样,两颗二项树组成一个,其中一个根节点较小二项树的根形成新树的根节点,另外一个作为其子树。如下图所示均是k阶二项树。
上图分别是、、。由定义可知,k阶二项树的节点的数量和必为偶数,且每颗k阶二项树由、、...组成,k指的是根节点下孩子节点的数量。而最右边的图所示不是k阶二项树。由此可以导出二项树有如下性质
性质1:k阶二项树的总节点数量为
归纳法可证。当k=0时,节点数量的为,假设的节点数量为,而是两颗组成的,所以的节点数量为+=,性质1得证。
性质2:二项树的高度为k(高度定义根节点到最远叶子节点上的简单路径上边的数目)
归纳法可证。当k=0时,的高度为0,假设二项树的高度为k-1,由于是由两颗合并而得,且合并后其中一颗作为了新树根的左子树,所以新树的高度=的高度+1=k-1+1,性质2得证。
性质3::在高度为的层次上,有(即)个节点
当k=1时,显然成立。假设上第层上节点数目,而是由两颗合并而得,合并后其中一颗作为了新树根的左子树,合并后新树第层节点的数量由原的第层的节点和作为左子树的的层节点的数量,设为total,即所以二项树的第层上的节点数量为
性质4:根节点的度(一个节点的度为一个节点的孩子数目)为k,如果根节点下孩子从左到右编号为k-1,k-2,...0,则孩子节点对应的是二项树
根据二项树的组成定义,可得到性质4
由于二项树的节点数必为偶数,作为优先队列的选择,不能满足奇数是个致命缺陷。那如何才能满足奇数呢,可不可以把不同度数的二项树“组合”起来,便可以满足奇数的要求,而且还可以满足堆性质,满足作为优先队列的条件。这些二项树“组合”起来的数据结构便是二项堆。
2 单个二项堆是由二项树组成的森林,森林中每颗二项树的度是唯一的,也就是有如下性质。
(1)在二项堆中,对每个,最多只有1个度为的二项树
(2)二项堆中的节点数量n与二进制数n有一定关系,具体如下图所示。为如下序列构建二项堆
从上述过程,可以观察到如下结论
(1)上述例子,节点n=8,其二进制为1000,对应位上即=1,=0,=0,=0,代表此二项堆只有一颗的二项树
(2)如果n=11,其二进制为1011,对应位上=1,=0,=1,=1,由三颗二项树组成、、组成。而对于每个数n,有其唯一的二进制表达式,所示对节点数为n的二项堆,其组成是唯一的。
性质3:二项堆有n个节点,其高度不大于
二项堆的高度取决于其森林中第一颗二项树的高度,也就是n转化的二进制数中的首位‘1’代表的二项树,当森林中只有一颗二项树时,高度最大,为,所以二项堆的高度不大于
性质4:二项堆有n个节点,其长度不大于+1
二项堆的长度定义二项堆森林中二项树的个数,也就是节点数n转化为二进制数中数位‘1’的个数。对于一个数n,其转化为二进制后的位数为+1,其中数位‘1’的个数必然不大于+1
2.1二项堆的存储
二项堆有如下三个指针
(1)父节点指针,指向此节点的父节点
(2)左儿子指针:指向最左的孩子
(3)右兄弟指针:指向此节点的右兄弟
如上图所示,最上层的是根节点链表,横向指针是右兄弟指针,向下的是左儿子指针,向上的是父节点指针,
2.2二项堆的操作如下
2.1.1· 合并操作
(1)待合并的2个二项堆森林合并一个二项堆森林
(2)新的二项堆执行合并过程(consolidation)。即按照度数从小到大,将度数一样的二项树进行合并,直至森林中不存在度数一样的二项树为止。
合并过程类似于二进制中的加法。如下图所示。
如上图所示,两颗二项堆的合并,从各自度数最小的二项树开始合并,如两个合并成一个,两个合并一个,如果两个堆都存在,则进位过来的保留,原堆上的两个合并成,如果对于,如果两个堆只有一个堆存在,则保留,如果两个堆都不存在,则不保留。
合并操作的伪代码如下:
def merge(A,B) //first 指针指向二项堆中最左侧的二项树
{
C=NULL
for(int i=0;i<A.degree()||i<B.degree();i++) //度数从小到大进行合并
{
if(tree(A,i)!=NULL)
C.add(tree(A.i)) //将二项堆A中度为i的二项树加入新堆。
if(tree(B,i)!=NULL)
C.add(tree(B.i))
}
consolidation(C)
return C
}
def consolidation(C)
{
while(C exists the same degree tree) //存在度相同的二项树
{
for(int i=0;i<C.degree();i++)
{
if(degree(x)==degree(y)) //两颗二项树度相同
{
if x.key<y.key
swap(x,y)
make y leftchild of x //将其中一颗作为另一颗的左子树
increase x.degree
}
}
}
二项堆的合并与每个二项堆的长度成正比,而长度不大于+1,所以合并节点数为n和m的二项堆的时间复杂度为+1++1=
2.1.2 插入操作
插入一个元素,将一个元素视为具有一个元素的二项树(),然后看作具有一个元素的二项堆与原有堆的合并,其伪代码如下:
def insert(A,x){ //在堆A插入节点x
B=MakeintoHeap(x)
return marge(A,B)
}
而合并的时间复杂度为,一个节点的二项堆的度为0,所以插入操作的复杂度为
2.1.3二项堆的构建
(1)二项堆的构建如本章开始部分的话,则是逐个插入法,其伪代码如下:
def create(queue q)
{
T=NULL
while(q!=null)
{
x=q.pop()
insert(x,T)
}
return T
}
用上述方法,其构建复杂度为,而根据stirling公式,所以构建复杂度为。
因为二项堆是可合并堆,可以采用合并法建堆。合并法的步骤是度数从0开始,按照顺序将度数相同的二项树两两合并,直至队列中不存在度数相同的二项树为止(此时队列中每个元素视为一颗二项树)。其实现过程如下:
合并法建堆的伪代码如下:
def create(list q)
{
for(int i=0;i<log(q.length);i++) //度从0开始
{
if(x.degree==i)//找到第一个度为i的节点
{
for(y=x->next,y!=NULL;y=y->next)
{
if(y.degree==i)
{
merge(x,y)//找到度相同的两个节点,进行合并
x=y->next
break;
}
}
}
}
return q
}
合并法建堆的时间复杂度如下。首先是对只有1节点(度为0)的队列进行合并次,其次对2个节点(度为1)的左偏树进行合并次,再次是4个节点(度为2)的左偏树进行合并次,...个节点的左偏树合并次,...最后对、个节点(在与两个整数之间取绝对值差值最小的,若n=7,为4;n=11,为4)的左偏树进行合并1次,所以总的复杂度为
2.1.4.删除最小值操作
删除最小值操作,即从二项堆中每个二项树的根节点中找到最小节点,然后删除最小节点,被删除根节点的二项树与其余的二项树执行“合并”过程,其位代码如下:
def extractMin(C)
{
find min in the root list
add min->left to the root List;
add min->right to the root List;
del min;
consolidation(C)
}
在根结点链表中,查找最小值最坏情况下为二相堆的长度,而长度不超过 +1,所以删除最小值的复杂度为
2.1.5 删除任意值操作
删除任意值指的是删除二项堆上已存在的值。删除任意值的步骤如下,首先找到这个任意值,设这个任意值所在的二项树称为T ,将此“任意值”和所在二项树T的根结点进行交换(即将要删除的节点“向上调整”至根节点),交换的过程要保持堆性质,交换完毕后,将新树T的左右子树改至根结点链表上,然后将更换完毕后新二项的根节点删除,剩下的部分执行“合并”,合并完后算法结束。删除任意值的操作过程 下。
删除任意值操作的伪代码如下:
def delany(T,x)
{
while(x.parent!=NULL)
{
swap(x,x.parent)
x=x.parent
}
del x
return consolidation(x.child,others)
}
删除任意值的时间复杂度如下。向上调整的复杂度不超过, 合并其左右子树和剩余二项树的复杂度不超过,所以删除任意值的操作复杂度为。删除任意值操作还可以划分为两种操作的集合,请参考复习题。
2.1.6 减小值的操作
减小值的操作类似于堆的操作,减小后要进行“向上调整”或“向下调整”以满足堆性质。其复杂度向上调整的复杂度不超过
3总结
二项堆是一种可高效合并的堆,其它操作均可以建立在“合并”操作的基础上。其常见操作的复杂度见下表。
二项堆操作 | 合并 | 插入 | 构建 | 删除最小值 | 删除任意值 | 减小值 |
复杂度 |
4 复习题
(1)请解释二项堆和二项树的区别和联系
(2)在2.1.5中说到删除任意值的操作可以分为两个操作的集合,哪两个?(答:减小值和删除最小值。先将要删除的值减小为,然后执行删除最小值操作)
参考资料:
1 Handbook of Data Structures and Applications.Dinesh P.Mehta and Sartaj Sahni.2005
标签:Binominal,删除,复杂度,合并,如下,Heap,节点,二项 来源: https://blog.csdn.net/robator/article/details/113185930