选择排序
选择排序的复杂度是。
选择排序的算法思想是:找到数组中最小的元素,与第一个元素交换位置;找到剩下的最小的元素,与第二个元素交换位置;如此往复。
如果把排序应用在洗牌中,那么选择排序就是每次都翻遍牌堆,找到最小的牌,然后把它按顺序放在手牌里。牌堆被拿完的时候,手牌里就是排好序的一副牌了。
public static void selectionSort(int[] ints) {
for (int i = 0; i < ints.length; i++) {
int minIndex = findMin(ints, i, ints.length - 1);
int temp = ints[i];
ints[i] = ints[minIndex];
ints[minIndex] = temp;
}
}
public static int findMin(int[] ints, int indexFrom, int indexTo) {
int minIndex = indexFrom;
int min = ints[indexFrom];
for (int index = indexFrom; index <= indexTo; index++) {
if (min > ints[index]) {
min = ints[index];
minIndex = index;
}
}
return minIndex;
}
插入排序
插入排序的复杂度是。
插入排序更接近于抽牌的情形。人们在抽牌时,每次会从牌堆中随机抽到一张牌,然后将这张牌放在手牌的合适位置。这就是插入排序。
举个例子,如果手牌中是有序的4589,而此时抽到一张7,那么重新排序后的手牌应该是45789。插入排序就是在不断重复这个过程。
public static void insertionSort(int[] ints) {
for (int i = 0; i < ints.length; i++) { // 每个循环抽一张牌ints[i],插入到手牌ints[0]~ints[i-1]中
for (int j = i - 1; j >= 0; j--) {
if (ints[j] > ints[j + 1]) {
int temp = ints[j];
ints[j] = ints[j + 1];
ints[j + 1] = temp;
}
}
}
}
在上面的代码中,外循环相当于抽牌的过程,内循环相当于排序手牌的过程。ints[i]就是抽到的牌,而ints[0]~ints[i-1]是已经排序好的手牌,ints[i+1]~是乱序的牌堆。
希尔排序
希尔排序是插入排序的升级版,利用了插入排序的几个特点:
- 元素越有序,插入排序进行交换的次数就越少,就越高效。
- 元素越少,插入排序的循环越少,就越高效。
所以,希尔排序先对数组的局部进行排序,然后对整个数组进行排序。
public static void shellSort(int[] ints) {
int h = 1;
while (h < ints.length / 3) {
h = 3 * h + 1;
}
while (h >= 1) {
for (int i = h; i < ints.length; i++) {
for (int j = i; j >= h; j -= h) {
if (ints[j] < ints[j - h]) {
int temp = ints[j];
ints[j] = ints[j - h];
ints[j - h] = temp;
}
}
}
h /= 3;
}
}