算法导论学习笔记(13)——二项堆
来源:互联网 发布:8月份上海房产成交数据 编辑:程序博客网 时间:2024/04/30 22:41
一颗二项堆由一组二项树组成,二项树Bk是一种递归定义的有序树,
B[k]是由两棵B[k-1]二项树组成,其中一颗树是另外一颗树的子树。
下面
(b)是B0 - B4的二项树:
(a)表示二项树Bk的递归定义,三角形表示有根的子树
(c)以另一种方式来看二项树Bk
显然二项树具有如下的性质:
1. 对于树B[k]该树含有2^k个节点;
2. 树的高度为k;
3. 在深度为i中含有Cik节点,其中i = 0, 1,2 ... , k;
4.根的度数为k,它大于任何其他节点的度数;并且,如果根的子女从左到右编号为k-1,k-2,···,0.子女i是子树 Bi 的根。
定义完二项树之后,下面来定义二项堆H,二项堆是由一组满足下面的二项树组成:
1. H中的每个二项树遵循最小堆性质;
2. 对于任意的整数k的话,在H不存在另外一个度数也是k的二项树;
另外定义:
1. 二项堆的度数定义成子女个数;
2. 定义二项堆的根表是二项树的根节点形成的链表;
好的,二项堆的定义完成之后,下面的问题就是我们在什么情况下使用“二项堆”?
如果是不支持所谓的合并操作union的话,普通的堆的数据结构就是一种很理想的数据结构。 但是如果想要支持集合上的合并操作的话,最好是使用二项堆或者是斐波那契堆,普通的堆在union操作上最差的情况是O(n),但是二项堆和斐波那契堆是O(lgn)。
二项堆中每个节点的类型:
1. parent:指向父节点
2. sibling:指向右边的兄弟节点
3. child:定义该节点的子节点
4. degree:定义该节点的度数
5. key: 定义关键字域
5. 其他应用场景中需要的卫星数据
}BinNode,*pBinNode;
对于定义的字段,对于根表中的节点和非根表中的元素是不相同的,根表中的节点的parent全部是空,sibling指向的是根表中的下一个元素;对于非根表中的节点的话,parent指向的是该节点的父节点,sibling指向该节点的兄弟节点。
typedef pBinNode pBinHeap;//二项堆
//创建一个空的二项堆
pBinHeap CreateBinHeap()
{
pBinHeap newHeap = (pBinHeap)malloc(sizeof(BinHeap));
memset(newHeap, 0, sizeof(BinHeap));
return newHeap;
}
//寻找最小关键字
pBinNode SearchMinKey(pBinHeap pHeap)
{
pBinNode y = NULL;
pBinNode x = pHeap->pHead;
int min = MAX;
while(x)
{
if (x->key<min)
{
min = x->key;
y = x;
}
x = x->sibling;
}
return y;
}
//连接两个二项堆
void Link(pBinHeap pH1, pBinHeap pH2)
{
pBinNode pH1Parent = pH1->parent;
pH1->sibling = pH1Parent->child;
pH1Parent->child = pH1;
++(pH1Parent->degree);
}
//将H1, H2的根表合并成一个按度数的单调递增次序排列的链表
pBinHeap Merge(pBinHeap pH1, pBinHeap pH2)
{
//heap->堆的首地址,H3为指向新堆根结点
pBinHeap heap = NULL, firstHeap = NULL, secondHeap = NULL, pre_H3 = NULL, H3 = NULL;
if (pH1 != NULL && pH2 != NULL)
{
firstHeap = pH1;
secondHeap = pH2;
//整个while,firstHeap, secondHeap, pre_H3, H3都在往后顺移
while (firstHeap != NULL && secondHeap != NULL)
{
if (firstHeap->degree <= secondHeap->degree)
{
H3 = firstHeap;
firstHeap = firstHeap->sibling;
}
else
{
H3 = secondHeap;
secondHeap = secondHeap->sibling;
}
if (pre_H3 == NULL)
{
pre_H3 = H3;
heap = H3;
}
else
{
pre_H3->sibling = H3;
pre_H3 = H3;
}
if (firstHeap != NULL)
H3->sibling = firstHeap;
else
H3->sibling = secondHeap;
}//while
}
else if (pH1 != NULL)
heap = pH1;
else
heap = pH2;
pH1 = pH2 = NULL;
return heap;
}
//合并两个二项堆
pBinHeap Union(pBinHeap pH1, pBinHeap pH2)
{
pBinHeap pre_x = NULL, x = NULL, next_x = NULL;
pBinHeap newH= CreateBinHeap();
newH = Merge(pH1,pH2);
if(newH == NULL) return newH;
x = newH;
next_x = x->sibling;
while (next_x)
{
if (x->degree != next_x->degree || ( next_x->sibling != NULL && next_x->sibling->degree == x->degree))
{
pre_x = x;
x = next_x;
}
else if (x->key <= next_x->key)
{
x->sibling = next_x->sibling;
Link(next_x,x);
}
else
{
if (pre_x == NULL)
newH = next_x;
else
pre_x->sibling = next_x;
Link(x, next_x);
x = next_x;
}
next_x = x->sibling;
}
return newH;
}
//插入一个节点到二项堆中
void Inerst(pBinHeap pH, BinNode node)
{
pBinHeap newH = CreateBinHeap();
node.parent = NULL;
node.child = NULL;
node.sibling = NULL;
node.degree = 0;
newH = &node;
pH = Union(pH,newH);
}
//抽取有最小关键字的结点
pBinHeap ExtractMin(pBinHeap heap)
{
pBinHeap pre_y = NULL, y = NULL, x = heap;
int min = INT_MAX;
while (x != NULL)
{
if (x->key < min)
{
min = x->key;
pre_y = y;
y = x;
}
x = x->sibling;
}
if (y == NULL)
{
return NULL;
}
if (pre_y == NULL)
{
heap = heap->sibling;
}
else
{
pre_y->sibling = y->sibling;
}
//将y的子结点指针reverse
pBinHeap H2 = NULL, p = NULL;
x = y->child;
while (x != NULL)
{
p = x;
x = x->sibling;
p->sibling = H2;
H2 = p;
p->parent = NULL;
}
heap = Union(heap, H2);
return y;
}
//减小关键字的值
void Decrease(pBinHeap pH, pBinNode x, int k)
{
pBinNode y,z;
if (k>x->key)
return;
x->key = k;
y = x;
z = y->parent;
while (z && y->key<z->key)
{
int tem = y->key;
y->key = z->key;
z->key = tem;
y = z;
z = y->parent;
}
}
//删除一个关键字
void Delete(pBinNode pH, pBinNode x)
{
Decrease(pH,x,-MAX);
ExtractMin(pH);
}
- 算法导论学习笔记(13)——二项堆
- 《算法导论》学习笔记—算法基础
- 算法导论学习笔记——基数排序
- 算法导论学习笔记——红黑树
- 算法导论学习笔记(6)——红黑树
- 算法导论学习笔记(12)——B树
- 算法导论学习笔记(20)——最大流
- 《算法导论》学习笔记(2)——快速排序
- 《算法导论》学习笔记(4)——红黑树
- 插入排序算法学习——算法导论学习笔记
- 冒泡排序算法分析——《算法导论》学习笔记
- 堆排序算法分析——《算法导论》学习笔记
- 算法导论学习笔记——快速排序算法
- 算法导论学习笔记——计数排序算法
- 算法导论学习笔记——贪心算法
- 算法导论学习笔记—Strassen算法的Java实现
- 《算法导论》学习笔记
- 《算法导论》学习笔记
- 分享我用Qt写的游戏组队群聊系统
- ActionServlet类未找到
- JDBC的支持——DataSource的配置
- 应用Python快速实现系统原型
- 通过反射技术创建窗体实例然后给控件赋值(C#)
- 算法导论学习笔记(13)——二项堆
- 利用OpenCV设定不规则ROI区域
- AndroidNote012.Android访问webservice.客户端登录注册
- JDBC数据处理步骤
- stallman 征婚
- 我要编程
- Property-Driven和Model-Driven
- android相关网址
- (转)获得Python脚本所在目录