算法自学笔记:堆排序

利用二叉堆的有序性质,可以利用其进行排序。堆排序分为以下两步:
1 重排列元素数组构成一个二叉堆。
2 不断返回最大元素(即根节点)直到堆为空

注:对于堆的方法可参考文章https://blog.csdn.net/Raine_Yang/article/details/122063624
1 从下至上构造堆
当然,我们可以对每个元素调用之前实现的insert()方法,但是这么做每一次定位都需要查找整个堆。一个更高效的查找方法是自下而上。
在这里插入图片描述

如图,我们可以把E-L-E这一部分当做一个子堆。我们逐层对各个子堆进行排序,这样得到最终整个堆也是有序的

	for (int i = N / 2; i >= 1; i--) {
		sink(i);
	}

如程序所示,从数组末尾子节点的父节点(N / 2)处开始,对各个子堆的根节点进行sink操作。在例图中将会遍历E, T, R, O, S,至此,堆构造完成。

2 下沉排序
对于构造完成的堆,根节点为最大值。因此我们首先将根节点和最末尾元素交换,此时最末尾元素排成,然后对新的根节点再进行sink操作以保证堆有序。重复此操作直至遍历完成所有元素。

注意这一方法类似于对各个元素调用优先队列里delMax方法,唯一不同的是我们不是把得到的最大值返回,而是存在数组末尾。

	while (N > 1) {
		exch(1, N--);
		sink(1);
	}

整个堆排序代码为:

// heap sort
	public void sort() {
		for (int i = N / 2; i >= 1; i--) {
			sink(i);
		}
		while (N > 1) {
			exch(pq, 1, N--);
			sink(1);
		}
	}

堆排序的性能:
构造堆操作时间复杂度为N,排序操作时间复杂度NlogN,因此整个排序时间复杂度为2NlogN

堆排序一大优点是它为原地排序,并且最糟情况下依然保存O(NlogN)时间复杂度级别。这一优势是快速排序和合并排序两大经典排序都不具备的(合并排序空间复杂度N,快速排序最糟情况时间复杂度N²)

但是堆排序也有一些缺陷。尽管同为NlogN级别时间复杂度,堆排序单次操作用时稍大于快速排序。并且堆排序由于要大幅在树上各索引跳跃,无法充分利用缓存,导致实际实施的效率低于理论值。另外,由于堆排序涉及长距离交换,它不稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值