【原理思路】二项堆各基本操作编程思路

来源:互联网 发布:java怎么防止sql注入 编辑:程序博客网 时间:2024/04/30 11:49

一个二项堆是由一组二项树组成的;


二项式树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);

0 0
原创粉丝点击