文章目录
- 插入排序
- 时间复杂度
- 空间复杂度
- 代码
- 希尔排序
- 时间复杂度
- 空间复杂度
- 代码
以从小到大排序为例进行说明。
插入排序
插入排序就是从前向后(i=1开始)进行选择,如果找到在i之前(分配一个j下标进行寻找)有比array[i]
大的数据,那就将其移动到后面(j+1处),每次小循环直到j < 0
为止,大循环直到i > array.length
为止。
- 小循环就是将
i
前面的元素进行遍历找出大的元素- 大循环就是遍历整个数组将
i处的元素
进行插入调整
时间复杂度
O(n2)
最坏的情况是:i 顺着把整个数组遍历一遍的同时,j 向前遍历每次都需要遍历至 -1;这样就会遍历n2次
- 所以插入排序最快是排一个
有序的数组
,每次都不同调,是O(n)- 最慢是排一个
逆序的数组
,每次都需要遍历,是O(n2)
空间复杂度
O(1)
没有额外的空间消耗
代码
public void insertSort(int[] array) {
// 从1开始是因为一个元素必定是有序的
for (int i = 1; i < array.length; i++) {
// 保存下来用于比较,不然i下标的值可能会由于j+1的赋值而发生改变
int tmp = array[i];
// 从i的前一个开始比较
int j = i - 1;
for (; j >= 0; j--) {
if (array[j] > tmp) {
// 如果比 tmp 大,那就应该将前一个数据挪到后一个
array[j+1] = array[j];
} else {
// 如果小于等于,那就说明从这个j开始前面的都是有序的,不需要再遍历了
break;
}
}
// 循环结束后,插入 tmp 的值
array[j+1] = tmp;
}
}
希尔排序
希尔排序是对于插入排序的改进,通过改变每次插入排序的间隔增量而达到优化的一种排序。
该排序定义了一个
gap 用于标识每次插入排序的分组
,其余于与插入排序无异。
时间复杂度
O(n1.3) ~ O(n1.5)
由于gap 的不同会导致排序的趟数不同,所以该算法并没有一个明确的时间复杂度。
空间复杂度
O(1)
没有额外空间开销
代码
public void shellSort(int[] array) {
int gap = array.length;
// 循环每次的以gap为增量的插入排序
while (gap != 1) {
gap /= 2;
shellSort(array, gap);
}
}
private void shellSort(int[] array, int gap) {
// i+=gap也可以,因为最后gap传进来总会是1,会进行一次完全态的插入排序
for (int i = 0; i < array.length; i++) {
int tmp = array[i];
int j = i - gap;
// 这里就是对间隔为 gap 的数据进行比较和插入
for (; j >= 0; j += gap) {
if (array[j] > tmp) {
array[j + gap] = array[i];
} else {
break;
}
}
// 与普通插入排序相同,需要在最后将被比较的数据还到该去的地方
array[j+gap] = tmp;
}
}