直接插入排序-原理:
整个区间被分为
- 有序区间
- 无序区间 :每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入。
基本思想:
直接插入插排的基本思想是:当插入第i(i >= 1)时,前面的array[0],array[1],……,array[i-1]已经排好序。这时,用array[cur]的排序码与V[i-1],V[i-2],…的排序码顺序进行比较,找到插入位置即将V[i]插入,原来位置上的元素向后顺移。
实现:
// 以升序排序为例
public static void insertSort(int[] array) {
// 有序区间: [0, bound)
// 无序区间: [bound, size)
for (int bound = 1; bound < array.length; bound++) {
// 处理 bound 位置的元素如何往前插入
int tmp = array[bound];
// 需要从后往前, 找到合适的位置进行插入.
int cur = bound - 1;
for (; cur >= 0; cur--) {
// 如果这里的条件写成了 array[cur] >= tmp, 此时就是不稳定排序了
if (array[cur] > tmp) {
// tmp 元素还需要往前去找. 同时就需要把 cur 位置的元素往后搬运
array[cur + 1] = array[cur];
} else {
break;
}
}
array[cur + 1] = tmp;
}
}
private static void Swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
性能分析:
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:稳定
插入排序,初始数据越接近有序,时间效率越高
希尔排序-原理:
希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取重复上述分组和排序的工作。当到达=1 时,所有记录在统一组内排好序。
- 希尔排序是对直接插入排序的优化。
- 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
实现:
public static void shellSort(int[] array) {
// size/2, size/4, size/8 ... 1
int gap = array.length / 2;
while (gap > 1) {
insertSortGap(array, gap);
gap = gap / 2;
}
// 当 gap 为 1 的时候, 再来一次最终插排
insertSortGap(array, 1);
}
// 分组情况下, 同组的相邻元素下标差 gap
private static void insertSortGap(int[] array, int gap) {
// 从每组的 [1] 的元素开始.
for (int bound = gap; bound < array.length; bound++) {
int tmp = array[bound];
// bound 位置中相邻的前一个元素下标
int cur = bound - gap;
for (; cur >= 0; cur -= gap) {
if (array[cur] > tmp) {
// 进行搬运, 把 cur 位置的元素搬到 cur + gap 位置
array[cur + gap] = array[cur];
} else {
break;
}
}
array[cur + gap] = tmp;
}
}
private static void Swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
希尔排序是直接插入排序的改进,我们在实现的时候,只要把gap看成1就好理解了。
性能分析:
时间复杂度:最坏情况下是O(n^2),最好情况下理论可以达到O(n ^1.3)
空间复杂度:O(1)
稳定性:不稳定