一、前言
本篇博客属于对排序算法的复习,主要是基于《算法》一书。博客正文聚焦的主要是算法的实现过程,对于辅助方法如 less()
、exch()
和 isSorted()
等请移步排序算法总结系列导读查看相关实现。
注: 本文中所有的图片均为《算法》一书的辅助图片,代码实现也源自该书。
本文只是对其要点的提炼,想要详细的学习这些算法请自行观看相关书籍。
二、正文
本篇博客将复习的三种排序算法是:
- 选择排序
- 插入排序
- 希尔排序
1. 选择排序
选择排序是最为简单的排序算法,基于其特点和复杂度,几乎不会使用到选择排序来解决实际的排序问题,但是它的思想对于我们入门排序算法是有一定指导意义的。
1.1 思想
首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换(如果第一个元素就是最小元素那么它就和自己交换)。再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换…如此往复,直到将整个数组排序。
1.2 代码实现
选择排序的 Java代码实现如下所示:
public class Selection {
public static void sort(Comparable[] a){
int n = a.length;
// 逐个扫描数组中的元素进行交换
for (int i = 0; i < n; i++){
int min = i; // 记录最小元素的索引
for (int j = i+1; j < n; j++){
if (less(a[j], a[min])){
min = j;
}
}
// 将a[i]和a[min]进行交换
exch(a, min, i);
}
assert isSorted(a);
}
// less()、exch()和isSorted()方法见本文开头
}
1.3 算法复杂度
对于长度为 N 的数组,选择排序需要大约 N 2 / 2 \ N{^2}/2 N2/2 次比较和 N \ N N 次交换。
证明。我们以对数组 [ S O R T E X A M P L E ] 进行排序证明这个复杂度。我们用一张 N ✖ N \ N✖N N✖N 的表格表示排序的轨迹,其中每个非灰色字符都表示一次比较。表格中大约有一半字符不是灰色的。而对角线上的每个元素都对应着一次交换。表格如下所示。
左边的 i 和 min 下面对应的数字分别表示要交换元素的数组下标和黑色元素中最小值所对应的数组下标。其中灰色的元素表示已经排定好的元素;黑色的元素表示在本次循环中进行比较的元素;红色的元素表示即将和 a[i] 交换的最小元素。
从上图可以清晰的看出,在长度为 N 的数组中,比较所需的次数大约为 N