堆-堆的基本概念与操作

堆(heap)又名优先队列(priority queue),是一种特殊的树。

1. 堆的两个性质:

① structure property: 是一个完全二叉树;
因此可用数组表示,BT[n+1]的形式,BT[0]为dummy.

② order property: (min heap为例,大小关系变反之后则为max heap)
表述一:每个子树的根的值都比子树中其他值小;
表述二:每个结点的值都比左右子小;
表述三:从根到任何叶的(唯一)路径上,结点的值递增;

2. 堆的父子结点

在这里插入图片描述
注:如果要从BT[0]开始保存堆,则以上公式应变为:
parent = ( i - 1 ) / 2 ;
left_child = 2 * i + 1 ;
right_child = 2 * i + 2 ;

3. 堆的基本操作
(1)Insertion

我们采用的方法是
先把将入结点无脑放入最高层右边(先满足structure property)
再对该结点进行percolate up操作(再满足order property)

其实放入最高层右边后,堆只有从根到它的这一条路径的顺序受到了影响,因此只需要用percolate up操作调整这一路的顺序。调整之后,这一条路上的所有结点值一定小于等于调整前的值,且仍保有递增性质,由此可知调整后的堆一定完全满足order property.

void  Insert( ElementType  X,  PriorityQueue  H ) 
{ 	
	if ( IsFull( H ) ) { Error( "Priority queue is full" ); return; } 
	int  i; 
	H->Elements[++H->Size] = X;
	
	 // 对暂时位于最末的X进行 percolate up
	 PercolateUp(H->Size, H);
//	for (i = H->Size; H->Elements[i / 2] > X; i /= 2) 
//		H->Elements[i] = H->Elements[i / 2]; 
//	H->Elements[i] = X; 
	
	return;
}

(2)DeleteMin

DeleteMin的本质就是删除根结点,且原则上对于堆的删除只能删除根节点。
我们采用的方法是
先把末尾结点值覆盖给根节点(先满足structure property)
再对根结点进行percolate down操作(再满足order property)

void DeleteMin( PriorityQueue  H ) 
{ 
    if (IsEmpty(H)) { Error( "Priority queue is empty" ); return  H->Elements[0]; } 

	int i, SmallChild;   
    ElementType X= H->Elements[H->Size--];  
    H->Elements[1] = X;
    
    // 对暂时位于根处的X进行 percolate down
    PercolateDown(1, H);
//    for (i = 1; i * 2 <= H->Size; i = SmallChild) { /* 如果不是叶(=有子=有左子)*/ 
//		SmallChild= i * 2; 
//        if (SmallChild!= H->Size  &&  H->Elements[SmallChild+1] < H->Elements[SmallChild])
//			SmallChild++; 
//	    /* 至此SmallChild已为较小的子节点 */
//		
//		if ( X> H->Elements[SmallChild] )   
//       	H->Elements[i] = H->Elements[SmallChild]; 
//		else break;
//    } 
//    H->Elements[i] = X; 
    
    return; 
}

(3)Percolate Up

p是被调整元素的位置(其实是被调整元素到根的那条路被调整)。

void PercolateUp(int p, PriorityQueue H)
{
	ElementType X = H->Elements[p];
	while (X < H->Elements[p / 2]) {
		H->Elements[p] = H->Elements[p / 2];
		p = p / 2;
	}
	H->Elements[p] = X;
	return;
}
(4)Percolate Down

p是被调整元素的位置(其实是被调整元素不断寻找较小子节点到叶的那条路被调整)。

void PercolateDown(int p, PriorityQueue H)
{ 
	int i, SmallChild;   
    ElementType X = H->Elements[p];  
    
    for (i = p; i * 2 <= H->Size; i = SmallChild) { /* 如果不是叶(=有子=有左子)*/ 
		SmallChild= i * 2; 
        if (SmallChild != H->Size  &&  H->Elements[SmallChild+1] < H->Elements[SmallChild])
			SmallChild++; 
	    /* 至此SmallChild已为较小的子节点 */
		
        if (X > H->Elements[SmallChild])   
        	H->Elements[i] = H->Elements[SmallChild]; 
        else break;
    } 
    H->Elements[i] = X; 
    
    return; 
}

值得注意的是

① 在percolate过程中,把被调整一路想成一个顺序排列的数组更好;
② 给了一个树,左右子树都是堆,把这个树调整成堆,所需要的的操作,可记作“左右堆变成堆”。
则有:percolate down操作 == “左右堆变成堆”操作。

(5)BuildHeap

给定一堆数,要求建立一个它们的堆。作N次Insertion是很慢的,由以上②引出了一种好方法,即先原序放入数组构成树,之后对每一个非叶子节点进行“左右堆变成堆”操作。 这是一种线性算法。以完美二叉树为例,它的各个节点的height值之和为O(N).

【Theorem】For the perfect binary tree of height h containing 2(h+1) - 1 nodes, the sum of the heights of the nodes is 2 h+1 - 1 - (h + 1).

void BuildHeap(PriorityQueue H)
{
	int i;
	for(i = H->Size/2; i >= 0; i--){	//H->Size/2是最末的非叶节点 其他非叶节点只需--
		PercolateDown(i, H);
	}
	return;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值