算法学习-数据结构-堆模板

堆是一种以数组形式存放数据的数据结构,并且也具有二叉树的某些性质的数据结构,因此可以使用堆可以很有效地方问和检索堆中的数据,很方便地对其进行插入和删除操作。

本文将会分成三个部分来介绍堆,

第一部分从堆的形式化的定义和堆中所定义的堆操作的接口定义。

第二部分给出堆接口定义中的方法实现,即算法复杂度的分析,最后实现一个以堆为类名的类模板的封装。

第三部分介绍在STL中如何使用堆来进行数据的排序

第四部分给出在ACM中使用堆来解决问题的问题和解题报告

poj 2010 & poj 2823 & poj2442 &poj3481&poj2051


第一部分:


1.堆的定义

n 个元素我们称之为堆,当且仅当它的关键字序列 k1 , k2 , k3 ..... , kn 满足:


    ;      ( 1.1 )


或者满足:

      ;   ;    (1.2)


我们把满足式子 1.1 的堆称之为最小堆, 而把满足式子 1.2 的堆称之为最大堆, 对于堆来说,可以从它的定义看出来,实质上它是一个完全二叉树。

如果树的高度为 d , 并约定根的层次为 0 , 则堆是具有如下性质的:

1,所有的叶节点不是出于第 d 层,就是出于 d-1 层。。

2,当 d >= 1 的时候, 在第 d-1 层上有 2^(d-1) 个节点 。

3, 第 d-1 层上如果有分支节点,则这些分支节点都集中在树的最左边。

4. 每个节点所存放元素的关键字,都大于(最大堆) 或 小于 (最小堆)其子孙节点所存放的关键字。


对于一个具有n个元素的堆,可以很方便地用如下的方法,有数组H来存取它。

1. 根节点通常存放在 H[1] 中。

2. 假定结点 x 存放在 H[i] , 如果它有左儿子,则左儿子节点存放在 H[2i] 中, 如果有右儿子节点,则右儿子节点存放在 H[2i+1] 中

3. 非根节点 H[i] 的父节点存放在    中。


堆操作的接口定义:


void sift_up ( Type H [] , int i ) ;
//作用是将堆中第 i 个元素上移 

void sift_down ( Type H [] , int n , int i );
//作用是将堆中的第 i 个元素下移

/**
在这里是这样的, 对于元素在堆中上移的时候,是从底到上进行不断比较,各个节点上面的元素的大小的,所以到根 H[1] 这个过程就会停止,
但是在元素堆中下移的时候,是需要通过堆中元素的大小从当前位置到 堆中最后一个元素进行比对的, 如果不指定最后一个元素的位置,或是堆中元素的多少的话,会造成越界访问的问题。
*/

void insert ( Type H [] , int &n , Type x ) ;
//该操作实现的是将元素 x  插入到堆中

Type delete ( Type H [] , int &n , int i ) ; 
//该操作实现的是将元素 x 从堆中删除,并且将删除的元素作为
//返回值进行返回

void make_head ( Type H [] , int n ) ;
// 使数组 H 中的元素按照堆结构从新的组织


好了, 第一部分结束,下面我们来看第二部分.


第二部分:


1. 元素上移操作

假定所使用的堆是最大堆。当修改了堆中某一个节点的关键字的数值的时候,使得这个关键字的数值大于它父亲的关键字,这就会打破最大堆中父节点大于两个子节点中的元素值的平衡,即违反了最大堆的性质。为了重新恢复最大堆的性质,需要把该元素上移到合适的位置。这个时候我们可以通过 sift_up 这个方法来使得整个堆再次恢复到平衡的状态。

其中,sift_up 操作会沿着 H[i] 到根 H[i] 的一条路线,把 H[i] 向上移动。 在移动的过程中, 把它和它的父节点进行比较,即比较 H[i] 和 H [i/2] 的大小,如果

H[i] > H[i/2] 的话, 则将置换 H[i] <-> H[i/2] 二者的位置。如此进行下去,直至H[i] 找到一个合适的位置为止。



/*
算法 1 元素的上移操作
输入: 数组 H [] 及被上移的元素在数组 H 中的下标 i
输出: 维持堆的性质的数组 H [] 
*/

template <class Type >
void sift_up ( Type H [] , int  i )
{
	bool done = false ;

	if ( i != 1 )
	{
		while ( !done && i != 1 )
		{
			if ( H [i] > H[i/2] )
				swap (H[i] , H[i/2]) ;
			else
				done = true ;
			i = i/2 ;
		}
	}
}

template < class Type >
void swap ( Type &a , Type &b )
{
	Type h = a ;
	a = b ;
	b = h ;
}


算法中的 i/2 操作是整出操作。在后面的算法中, 若是 a, b 是整数的话,则操作 a/b 均是表示的是整除操作。元素每进行一次移动,就会执行一次比较

操作。如果移动成功的话,他所在节点的层数就会-1. n 个元素一共有 (logn) 下取整,层的节点,所以sift_up 对应执行最多次数的操作是,i 的值是位于

堆的最下层,但是其 H[i] = Max ( H [k] )  1<=k<=n

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值