【leetcode学习笔记】堆排序、基数排序、排序算法总结

一、堆排序

1.1 堆

堆:堆是一种特殊的完全二叉树,大根堆是指任意一个结点的值大于它的两个孩子的值;小根堆是指任意一个结点的值小于它的两个孩子的值。

因为数组可以唯一对应完全二叉树,因此我们可以在数组结构中实现堆的相关工作。比如:对于结点i,它的父结点为(i-1)//2,它的左子结点为2i+1,右子结点为2i+2。

1.2 堆排序的核心思想

第一步:将数组转化为大根堆

从一棵空树出发,一个一个点加入,每次加入一个点,都通过一定的操作,使其变成一个大根堆。具体操作为,每一次将新的点放到最后一个叶结点,然后和它的父结点做比较,如果它的值大于父结点的值,那么就交换两个值。然后继续循环,直至它的值小于父节点,或者变成头结点。这样,每次加入一个点以后,我们仍能保持树的大根堆结构。

第二步:将大根堆转化为升序序列

首先,将大根堆的根结点,和最后一个叶结点交换,那么最后一个点就有序了。然后再把剩下的结点构成的树还原成一个大根堆。然后再把根结点,和倒数第二个叶结点交换,这样后两个点就有序了,再把剩下的树还原成一个大根堆。如此重复下去,就可以将大根堆的元素一个个弹出,最后就得到了升序数组。

还原大根堆的方法:将根结点向下比较,如果不是大根堆,就和两个孩子的最大值交换,直至树变成大根堆。

二、不基于比较的排序

2.1 核心思想

利用数据的内部结构进行排序。

例:对公司员工的年龄排序,我们知道员工年龄必然介于1-200,因此我们只需要准备一个200维的数组,然后我们遍历所有员工,23岁就让数组的23号元素加1,遍历过一次之后,我们就得到了每个年龄的员工数量,那么我们就可以还原出一个有序的年龄数组。

2.2 局限性

这种排序方法强依赖于数据的内部结构,就上例而言,年龄构成的是一个“有序”的“有限”集,所以我们才能设计出O(n)的算法。如果我们的数据范围是[-2^-32, 2^32 - 1]的话,我们再设置一个计数数组,就不是很划算了。

2.3 基数排序

假设给若干个4位数,准备10个桶,根据所有数的千位放到对应的桶中,那么9xxx的桶中的数一定比8xxx的桶中的数大,我们就只需要在每个桶内,对所有数的百位再分桶,如此迭代下去即可。

基数排序之所以可以免于比较,是因为“数”本身是有“进制”这个概念的,如果我们想要比较的东西没有“进制”的概念,那就没法用基数排序了。

三、排序算法总结

3.1 排序算法的稳定性

两个相等的数,在经过排序后,是否仍能保持原先的次序。稳定性在基础类型数据中一般不起作用,因为2和2谁先谁后并无所谓。但是在特定场景下,就有意义了。比如说excel的排序功能,原表有“班级”和“年龄”两个列,如果对“年龄”排序,我们希望在“年龄”值相等时“班级”列仍能保持原先的顺序,那么只有具备稳定性的排序算法才有这样的能力。

选择:[2,2,1],第一步1和第一个2交换,不稳定

插入:可以设置相等时插到右边,稳定

冒泡:可以设置相等时不交换,稳定

归并:归并时可以设置相等时,指针优先走左半边,稳定

堆排:每一个结点只能看到它的上下最多三个点,其余的点看不到,不稳定

快排:不稳定

3.2 O(nlog n)的算法比较

堆排序:额外空间复杂度O(1)

快速排序:速度快,O(nlog n)对应的常数较小

归并排序:稳定

因此一般情况下,我们都选用速度最快的快速排序。如果我们希望节省空间,那么就采用堆排序。如果对稳定性有要求,就选用归并排序。

基于比较的排序:

  • 目前为止,没有算法能使得时间复杂度优于nlogn。
  • 目前为止,没有算法能使得时间复杂度O(nlogn),空间复杂度O(1),且稳定。

3.3 排序算法的常见坑

  • 归并排序的空间复杂度能否变成O(1)?可以,有内部缓存法,但是不稳定,那为什么不直接用堆呢?
  • 原地归并排序能让归并排序的空间复杂度变成O(1),但是会让时间复杂度变为O(n^2),那为什么不直接用插入呢?
  • 快速排序能不能稳定?可以,有0-1 stable sort,但是空间变成O(n),那为什么不直接用归并呢?
  • 面试题:一个整数数组,要求找到时间O(n),空间O(1)的方法,使得数组变为奇数在左,偶数在右,且奇数的相对次序不变,偶数的相对次序不变?答案:不存在,如果存在,那么我们就能构建稳定的快速排序算法。因为把奇偶保持次序的分为两部分,等价于将小值和大值保持次序的分为两部分。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值