算法导论学习笔记(13)——二项堆

本文介绍了二项堆的基本概念,包括二项树的定义及其性质,并详细讲解了二项堆的操作实现,如创建、合并、插入节点等。同时对比了二项堆与普通堆在合并操作上的效率差异。

一颗二项堆由一组二项树组成,二项树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. 其他应用场景中需要的卫星数据

typedef struct _bin_node {
struct _bin_node* parent;
struct _bin_node*  sibling;
struct _bin_node* child;
unsigned int degree;
        int key;

}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);

}

程序猿可能都知道 数据结构算法 = 程序 ,慧眼识金的人懂得下下载这本算法导论的想必也知道它的经典,这是本清晰度还不错的pdf版本,外面好多资源,但都有内容不全的问题,这本是难得的全书,不用费力下载part 1234...了,分享给大家 《算法导论((美国)Cormen)[PDF] 第二版,2006年出版的 目录: 第一部分 基础知识 引言 第1章 算法在计算中的作用 1.1 算法 1.2 作为一种技术的算法 第2章 算法入门 2.1 插入排序 2.2 算法分析 2.3 算法设计 2.3.1 分治法 2.3.2 分治法分析 第3章 函数的增长 3.1 渐近记号 3.2 标准记号和常用函数 第4章 传归式 4.1 代换法 4.2 递归树方法 4.3 主方法 4.4 主定理的证明 4.4.1 取正合幂时的证明 4.4.2 上取整函数和下取整函数 第5章 概率分析和随机算法 5.1 雇用问题 5.2 指示器随机变量 5.3 随机算法 5.4 概率分析和指示器随机变量的进一步使用 5.4.1 生日悖论 5.4.2 球与盒子 5.4.3 序列 …… 第二部分 排序和统计学 引言 第6章 排序 第7章 快速排序 第8章 线性时间排序 第9章 中位数和顺序统计学 第三部分 数据结构 第10章 基本数据结构 第11章 散列表 第12章 二叉查找树 第13章 红黑树 第14章 数据结构的扩张 第四部分 高级设计和分析技术 导论 第15章 动态规划 第16章 贪心算法 第17章 平摊分析 第五部分 高级数据结构 概述 第18章 B树 第19章 二项 第20章 斐波那契 第21章 用于不相交集合的数据结构 第六部分 图算法 引言 第22章 图的基本算法 第23章 最小生成树 第24章 单源最短路径 第25章 每对项点间的最短路径 第26章 最大流 第七部分 算法研究问题选编 引言 第27章 排序网络 第28章 矩阵运算 第29章 线性规划 第30章 多项式与快速傅里叶变换 第31章 有关数论的算法 第32章 字符串匹配 第33章 计算几何学 第34章 NP完全性 第35章 近似算法 第八部分 附录:数学基础知识 引言 A 求和 B 集合等离散数学结构 C 计数和概率 参考文献 索引
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值