1.插入排序
时间复杂度:最坏情况下为O(N*N),此时待排序列为逆序,或者说接近逆序
最好情况下为O(N),此时待排序列为升序,或者说接近升序空间复杂度:O(1)
public void insertSort (int[] a) {
int sentinel; //哨兵,用来记录可能会因移动数组而覆盖掉的数
int j; //已排好序的数组的最大下表
for (int i = 1; i < a.length; i++){
sentinel = a[i]; //记录当前数
j = i - 1; //i前面的数都是已经排好序的,第一轮时,j=0,默认第一个a[0]已经排好
//移动前面排好的数组,找到比哨兵小的第一个数
//j是0-j都比哨兵大而结束循环,j = -1
while (j >= 0 && sentinel < a[j]){
a[j + 1] = a[j]; //向后移动排好序的数组
j--;
}
a[j + 1] = sentinel; //a[j]是比哨兵小的第一个数,因此j+1才是哨兵插入的位置
}
}
2.快速排序
时间复杂度:O(N*logN)
空间复杂度:O(N)
public void quickSort(int[] arr, int low, int high) {
// 终止条件,高低指针重合或相反
if (low >= high) return;
// 哨兵划分操作(以 arr[low] 作为基准数),哨兵,将所有比哨兵小的移到左边,比哨兵大的移到右边
int i = low, j = high;
while (i < j) {
while (i < j && arr[j] >= arr[low]) j--; //找到比哨兵小的high位
while (i < j && arr[i] <= arr[low]) i++; //找到比哨兵大的low位
swap(arr, i, j); //将大的交换到右边,小的交换到左边,注意,哨兵位置在0,并没有交换
}
swap(arr, i, low); //将哨兵移动到i位上,执行完此行,完成真正的划分,哨兵左边为小,右边为大
// 递归左(右)子数组执行哨兵划分
quickSort(arr, low, i - 1); //因为哨兵已经将小的移到左边,大的移到右边,因此无需传哨兵位置
quickSort(arr, i + 1, high);
}
public void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
3.希尔排序 - 插入排序增强版
时间复杂度平均:O(N^1.3)
空间复杂度:O(1)
public void ShellSort(int[] arr) {
int interval = arr.length / 2; //每次对gap折半操作,将间隔为gap的元素视为一组
while (interval >= 1) {
//对每组插入排序
for (int i = interval; i < arr.length; i++){//每个i对应的组,对i及左边同一组的元素进行插入排序
int sentinel = arr[i]; //哨兵
int j = i - interval;
while (j >= interval - 1 && sentinel < arr[j]){
arr[j + interval] = arr[j];
j = j - interval;
}
arr[j + interval] = sentinel;
}
}
}
4.选择排序