数据结构与算法系列之常用算法:排序算法
〇、前言
<<数据结构与算法系列之总篇>>
一、排序算法
上图框出的是比较常用的排序算法,归排、快排、堆排怎么选?
- 没有特殊要求,快排优先:常数项比堆排小,空间复杂度比归排小
- 若要求稳定,则选归排
- 若要求空间复杂度,则选堆排
01、冒泡排序
02、选择排序
03、插入排序
04、希尔排序
05、快速排序
06、归并排序
07、堆排序
08、桶排序
09、计数排序(广义来说属于桶排序)
10、基数排序(广义来说属于桶排序)
二、Java排序
JDK 的排序算法是综合了插入排序、快速排序、归并排序各自的优势得出的综合性排序算法:
- 样本小的时候,用插入排序,是充分利用其常数项系数小的优势
- 样本大的时候,使用快速排序和归并排序是充分利用其调度优势
a. 对于基本类型的数组,使用快速排序,是因为基本类型的数组不用考虑排序算法的稳定性
b. 对于引用类型的数组或集合,使用归并排序,是因为引用类型的数组或集合需要考虑排序算法的稳定性
1、DualPivotQuicksort.sort
根据数组的元素个数、nearly sorted和元素类型等来选择具体排序算法。例如对整数排序:
if (元素个数 < 47) {
插入排序
return;
}
if (元素个数 < 286) {
双轴快排
return;
}
// 判断数组是否是nearly sorted:统计数组中有序段的个数(包括正序和逆序),
// 如果有序段的个数 < 67,那么说明数组是nearly sorted,使用归并排序,归并所有有序段;
// 否则,说明数组不是nearly sorted,使用双轴快排
if (nearly sorted) {
归并排序
} else {
双轴快排
}
2、Arrays.legacyMergeSort
一个遗留个归并排序算法,未来的版本中将会淘汰,这里不予探究。
3、Timsort.sort | ComparableTimSort.sort
二分插入,一种优化的插入排序:标准插入排序是循环遍历查找元素的插入位置,而二分插入则是通过二分查找来找到元素的插入位置。
Timsort简单来说就是,分段 -> 利用插入排序(通过头部有序序列和二分插入优化)使其有序 -> 将有序段归并 -> 完成排序
4、为何Java不使用堆做纯排序
- 从cpu缓存的角度,堆是跳跃操作数组的,无法利用cpu缓存预读;
- 从nearly sorted角度,如果一个数组很多部分都是有序的,使用堆排序,会将其先打散,反而效率不如快速排序和归并排序;
- 堆是用数组实现的,要求内存连续,数据量大的时候不合适;
三、总结
JDK提供的排序算法很好,根据自己特定场景选择用JDK的还是自己实现。
作者:尜尜人物