在这里用对数组从小到大排序的例子来分析一下几种常用的排序算法:选择排序、插入排序、希尔排序、归并排序、快速排序
开始之前:
1、我们这里以实现了Comparable接口的数据为排序对象
2、两个工具方法:判断数组中两个元素一个是否比另一个小、互换数组中两个元素的值。实现如下:
public static boolean less(Comparable[] comparables, int i, int j) {
if (comparables[i].compareTo(comparables[j]) < 0) {
return true;
}
return false;
}
private static void exchange(Comparable[] comparables, int i, int j) {
Comparable x = comparables[i];
comparables[i] = comparables[j];
comparables[j] = x;
}
1、选择排序
选择排序的思想是,每一次循环,从剩余元素中取出最小的元素,放在已经排好序的数组元素的末端,例如有数组a[],长度为length,第0次从a[0]...a[length-1]中取出最小的元素a[x],将a[x]和a[0]互换位置,第1次从a[1]...a[length-1]中取出最小的元素a[y],将a[y]和a[1]互换位置。也就是说,第i次从a[i]...a[length-1]中取出最小的元素和i处的元素互换位置,直到i为数组的最后一个元素为止。
代码实现:
private static void sort1(Comparable[] comparables) {
for (int i = 0; i < comparables.length - 1; i++) {
int min = i;
for (int j = i + 1; j < comparables.length; j++) {
if (less(comparables, j, min)) {
min = j;
}
}
exchange(comparables, i, min);
}
}
性能分析:
- 比较次数:length-1+(length-2)+...+1,也就是大概为length*length/2
- 交换次数:length-1
- 运行时间和输入原始数组的顺序无关。
插入排序可以类比我们平时打扑克时候抓牌,每次新抓一张牌,将其插入到已经排好序的手中的牌组中。将这个过程抽象一下,那就是,桌子上的所有的牌就是我们待排序的数组,每次抓一张牌,就相当于每次从数组中取出一个元素,将其插入到已经排好序的手中的牌组中,就相当于,将新抓的这张牌和手中的牌组进行比较,从手中牌组中最大的这张牌开始进行比较,如果比这张牌大,那么放在其后边,继续抓牌,如果比这张牌小,放在其左边,然后再跟前一个元素进行比较,依次类推,直到新抓的这张牌遇到比它小的牌或者移动到手中牌组的起始位置为止。
代码实现:
public static void insertCompare(Comparable[] comparables) {
for (int i = 1; i < comparables.length; i++) {
for (int j = i; j > 0 && less(comparables, j, j - 1); j--) {
exchange(comparables, j, j - 1);
}
}
}
性能分析:
- 比较次数:最少length-1次,最大1+2+3...+(length-1)
- 交换次数:最少0次,最大1+2+3+...+(length-1)
- 运行时间和输入的原始数组的书序有关
3、希尔排序