【堆排序】优先队列

1、堆

堆,又可以称为二叉堆,可以看做一个近似的完全二叉树,除了最下面一层,其余每层都是填满的,且是从左向右填充。

A表示一个堆,堆的相关概念:
(1)A.length :数组元素的个数。注意数组中不是所有元素都是有效的。
(2)A.heap-size:数组有效元素的个数,0<=A.heap-size<=A.length
(3)PARENT(i):给定一个下标 i,它的父节点是 i/2,即

PARENT(i)
	return i/2;

(4)LEFT(i):给定一个下标 i,它的左孩子节点是 2i

LEFT(i)
	return 2i;

(5)RIGHT(i):给定一个下标i,它的右孩子节点是 2i+1

RIGHT(i)
	return 2i+1;

堆分为最大堆和最小堆,最大堆是指除了根结点以外,其结点都要满足父结点不小于其本身,即

A[PARENT(i)]>=A[i]

最小堆是指除了根结点以外,其他结点要满足父结点不大于其本身,即

A[PARENT(i)]<=A[i]

对兄弟结点则没有明确要求。

1.1、堆维护

堆维护是指维护堆的性质的过程,用函数 MAX-HEAPIFY (维护最大堆)和 MIN-HEAPIFY (维护最小堆)来表示。比如往当前堆里增加数据或从当前堆里减少数据,都要使改变后的堆依然是最大堆或者最小堆。它的输入是一个数组A 和 下标 i,假设以 LEFT(i) 和 RIGHT(i) 为根结点的树都满足最大堆或者最小堆的性质,现在需要维护以 i 下标元素为根结点的子树满足最大堆或最小堆性质

维护最大堆的伪代码如下:

MAX-HEAPIFY(A,i):
	# 对比当前结点与其左孩子、右孩子的值的大小,大的调整为父结点
	l = LEFT(i);
	r = RIGHT(i);
	# largest用于记录比较二者的较大值
	largest = [i]
	# 比较左孩子的值和当前值,如果左孩子的值大,令 largest为左孩子的下标
	if l<=A.heap.size and A[l]>A[largest]
		largest = l;
	# 比较largest和右孩子的值,如果右孩子的值大,令 largest为右孩子的下标
	if r<=A.heap.size and A[r]>A[largest]
		largest = r;
	# 如果 i 和 largest 不等,说明发生了变动,根结点和largest对应的结点交换
	if i ≠ largest
		exchange A[i] and A[largest];
		MAX-HEAPIFY(A,largest);

最小堆的维护过程:

MIN-HEAPIFY(A,i):
	l = LEFT(i);
	r = RIGHT(i);
	smallest = i;
	if l<=A.heap-size && A[l]<A[smallest]
		smallest = l;
	if r<=A.heap-size && A[r]<A[smallest]
		smallest = r;
	if i ≠ smallest
		exchange A[i] and A[smallest];
		MIN-HEAPIFY(A,smallest)

注意堆维护函数的大前提:以 LEFT(i) 和 RIGHT(i) 为根结点的树都满足最大堆或者最小堆的性质。只有满足了这个前提条件,比较 A[i]A[LEFT(i)]A[RIGHT(i)]才有意义

1.2、建堆

知道怎么维护堆以后就可以开始建堆。
建堆可以调用堆维护函数,建堆伪代码如下:

BUILD-MAX-HEAP(A):
	A.heap-size = A.length;
	for i = ⌊A.heap-size/2⌋; i>=1; i--
		MAX-HEAPIFY(A,i)

这里为什么要从下标为 ⌊A.heap-size/2⌋ 的结点开始维护?因为使用堆维护函数的一个前提就是输入的下标 i 的左右子树都满足最大堆或者最小堆的性质。这里要用堆维护函数,就得保证从最底层往上的第一个拥有子树的结点的左右子树满足最大堆或最小堆的性质,所以要从最底层往上的第一个拥有子树的结点开始维护,而这个结点的下标就是 ⌊A.heap-size/2⌋
同理,最小堆的建堆函数为

BUILD-MIN-HEAP(A):
	A.heap-size = A.length;
	for i = ⌊A.heap-size/2⌋; i>=1; i--
		MIN-HEAPIFY(A,i)

2、优先队列

优先队列是一种用来维护一族元素构成的集合的数据结构,它的底层数据结构可以用二叉堆实现。它提供的操作有:
(1)INSERT(A,x): 把元素x插入A中
(2)MAXIMUM(A) / MINIMUM(A): 返回A中最大/最小元素
(3)EXTRACT-MAX(A) / EXTRACT-MIN(A): 返回并删除A中最大/最小元素
(4)INCREASING(A,x,key) / DEREASING(A,x,key) : 把A中元素x的值增加/减少至key

如果底层用了二叉堆这种数据结构,那么上面的操作就很好实现了。因为A满足了最大堆或最小堆的性质,那么根结点就是A中最大元素或者最小元素

MAXIMUM(A) / MINIMUM(A):

HEAP-MAXIMUM(A):
	return A[1]
HEAP-MINIMUM(A):
	return A[1]

EXTRACT-MAX(A) / EXTRACT-MIN(A):

HEAP-EXTRACT-MAX(A):
	if A.heap-size<1
		error;
	max = A[1];
	A[1] = A[A.heap-size];
	A.heap-size--;
	MAX-HEAPIFY(A,1);
	return max
HEAP-EXTRACT-MIN(A):
	if A.heap-size<1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值