【一周刷爆LeetCode,算法大神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解(马士兵)】https://www.bilibili.com/video/BV13g41157hK?p=4&vd_source=04ee94ad3f2168d7d5252c857a2bf358
目录
笔记:
3、桶排序 & 其他排序算法
3.1 堆 & 优先级队列
3.1.1 堆
大根堆的heapify:把父节点和两个子节点中较大的那个进行交换
3.1.2 优先级队列
核心就是堆结构,堆顶就是优先级大的。
例题1:对一个几乎有序的数组,请选择一个合适的排序算法对它进行排序。几乎有序指的是如果要把数据按序排好,每个元素的移动距离不可以超过k。k是相对数组元素数量n较小的数。
数组内存不够时,扩容一倍的操作的时间复杂度是O(N),因为要创建长度为2n的新数组然后把旧数组的n个数都遍历拷贝进去.
3.2 比较器
实质是重载比较运算符。它可以很好地应用在特殊标准的排序上。
比如定义了包含学生姓名、年龄、ID的结构,想要按照ID升序排列时可以这么写:
然后在具体调用时,把数组和比大小的方法传递给Arrays.sort(),格式:Arrays.sort(数组, new 排序方法名);
【补充:前面提到过对数器,是生成大样本随机数据来检验方法的性能。和比较器不同,不要弄混了这俩。】
也可以对堆结构运用比较器,对于arr[a]和arr[b],如果是大根堆的情况,元素的数值越大则元素的下标越小:
如果返回负数,则第一个参数应该放在前面;
如果返回0,则谁在前都无所谓;
如果返回正数,则第二个参数应该放在前面;
3.3 桶排序
3.3.1 桶排序1.0
时间复杂度O(N),额外空间复杂度O(N)。
桶排序是不基于比较的排序。直接按元素每个数位上的数字放入对应桶中,再按桶的顺序取出,最终得到有序数组。
举例,数组包含25、13、17、100、72,问桶排序的具体执行过程是?是几进制的数 就开辟出几个桶。先用0补足位数,变成025、013、017、100、072。再分别遍历每个元素的个位数、十位数,百位数。每次遍历都是把元素放进桶里后,从左到右逐个取出桶里的元素。每个桶是先进先出;
缺点是应用范围有限,需要样本的数据状况能满足桶的划分。
3.3.2 桶排序2.0
遍历统计数组元素中个位十位、百位等数字的个数。但和桶排序1.0所不同的是,桶排序1.0只统计某数位为X的元素数量,而桶排序2.0统计的是某数位上小于等于X的元素数量。然后从右往左遍历数组,把数逐个填入数组的同时当前数位上的统计量减一。
3.4 稳定性
算法的稳定性指的是值相同的元素经过排序后,是否仍保留着原先的相对次序。
比如下图中的两个1,若排序后仍能保证①在②前面,该排序算法就是稳定的。
总而言之,只要不是相邻位置交换,其他交换方式都容易破坏稳定性.
算法 | 时间复杂度 | 空间复杂度 | 稳定性 |
选择排序 | O(N^2) | O(1) | ❌ |
冒泡排序 | O(N^2) | O(1) | ✔ |
插入排序 | O(N^2) | O(1) | ✔ |
归并排序 | O(NlogN) | O(N) | ✔ |
快排 | O(NlogN) | O(logN) | ❌ |
堆排 | O(NlogN) | O(1) | ❌ |
补充:
(1)“归并排序内部缓存法”可以把额外空间复杂度变为O(1),但比较难。
(2)快排的”01 stable sort“方法可以做到具有稳定性,但也很难。
面试题:把奇数放到数组左侧,偶数放在数组右侧,且要求具有稳定性(即相同元素具有原始的相对次序)。
回答:经典快排由于partition操作是0、1标准,思路可以应用于奇偶排列,但却无法奇数和偶数内部的相对次序,无法满足稳定性。
所以下次遇到这个问题,可以丢回给面试官。