一个二项堆是由一组二项树组成的;
二项式树Bk有如下性质:(k可为0)
(1)共有2^k个结点;
(2)树的高度为k;
(3)在深度i处有(k,i)(k!/i!/(k-i)!)个结点;
(4)根的度数为k,它大于任何结点的度数;如果从根的子女从左到右编号为k-1,k-2,....0,子女i是子树Bi的根;
两种视图看二项树如下:
二项堆的性质
(1)二项堆的每个二项树都遵循最小堆性质,结点的关键字大于或等于其父节点的关键字;
(2)对于任意非负数k,在H中至多有一颗二项树的根具有度数;
(3)一颗具有n个结点的二项堆,包含至多的lgn+1棵二项树;
(4)二项树的表示:
(4.1)使用左孩子,右兄弟的表示方式存储;
(4.2)每个节点都有一个关键字其其他应用要求而定的卫星数据;
(4.3)每个节点包含指向父节点的指针parent;(根节点,该域为空);
(4.4)指向其最左的孩子的指针l_child;(节点没有孩子,该域为空);
(4.5)指向其邻近右兄弟的指针r_sibling;(父节点最右的孩子,该域为空;对于根节点指向下一个根,而非根节点是指向其邻近右兄弟);
(4.6)包含度数域degree;
(5)有头指针Head指向第一个根;
(6)遍历根表时,各根的度数是严格递增的;
二项堆寻找最小关键字
(1)由二项堆的性质,最小关键字必在根节点中,故遍历一下根表即可;
(2)时间复杂度为O(lgn),空间复杂度为O(1);
合并两个二项堆
(1)合并两个二项堆前,先要把这两个堆合并成一个按度数递增次序排列的链表;
(2)此时有4钟情况,需要考虑,具体是下图:
(2.1)对于情况1,degree(x) != degree(x->next) ,只需往后面移动即可;
(2.2)对于情况2,degree(x) = degree(x->next) =degree(slibing(x->next)),也只是往后移动,就到了情况3或情况4;
(2.3)对于情况3,degree(x) = degree(x->next)!=degree(slibing(x->next)),当key(x) <= key(x->next)时的情况;
(2.4)对于情况4,degree(x) = degree(x->next)!=degree(slibing(x->next)),当key(x) > key(x->next)时的情况;
(3)时间复杂度为O(lgn),空间复杂度为O(1);
二项堆的节点插入
(1)可以将这个节点看成是一个只有一个节点的二项堆;执行上面的二项堆合并过程;
(2)时间复杂度为O(lgn),空间复杂度为O(1);
抽取具有最小关键字的节点
(1)其实就是将某个二项树的最小值,各子树抽离出来,依旧按照上面的要求排序后,按合并两个二项堆的规则重新组成一个二项堆;
(2)时间复杂度为O(lgn),空间复杂度为O(1);
减小关键字的大小
(1)若更新值k>原来key,则返回错误;各孩子的值是乱序的;增大关键字的大小见下面的操作;
(2)若更新值k<原来key,则向上回溯哦,找到合适的位置;
(3)时间复杂度为O(lgn),空间复杂度为O(1);
删除关键字
(1)将该关键字的大小变为-oo;执行上面的减小关键字的大小过程
(2)将该关键字的大小变为-oo;执行上面的抽取具有最小关键字的节点过程
(3)时间复杂度为O(lgn),空间复杂度为O(1);
增大关键字的大小
(1)先删除关键字,然后再插入二项堆的节点;
(2)时间复杂度为O(lgn),空间复杂度为O(1);