数据结构与算法系列之常用算法:排序算法

〇、前言

<<数据结构与算法系列之总篇>>

一、排序算法

image

上图框出的是比较常用的排序算法,归排、快排、堆排怎么选?

  1. 没有特殊要求,快排优先:常数项比堆排小,空间复杂度比归排小
  2. 若要求稳定,则选归排
  3. 若要求空间复杂度,则选堆排

01、冒泡排序

02、选择排序

03、插入排序

04、希尔排序


05、快速排序


06、归并排序

07、堆排序

08、桶排序


09、计数排序(广义来说属于桶排序)

10、基数排序(广义来说属于桶排序)


二、Java排序

JDK 的排序算法是综合了插入排序、快速排序、归并排序各自的优势得出的综合性排序算法:

  1. 样本小的时候,用插入排序,是充分利用其常数项系数小的优势
  2. 样本大的时候,使用快速排序和归并排序是充分利用其调度优势
    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不使用堆做纯排序

  1. 从cpu缓存的角度,堆是跳跃操作数组的,无法利用cpu缓存预读;
  2. 从nearly sorted角度,如果一个数组很多部分都是有序的,使用堆排序,会将其先打散,反而效率不如快速排序和归并排序;
  3. 堆是用数组实现的,要求内存连续,数据量大的时候不合适;

三、总结

JDK提供的排序算法很好,根据自己特定场景选择用JDK的还是自己实现。

posted @ 2020-01-08 15:38  尜尜人物  阅读(893)  评论(0编辑  收藏  举报