各类算法时空复杂度、稳定性对比

归并和快排是重点

排序算法

平均时间复杂度

最坏时间复杂度

空间复杂度

是否稳定

冒泡排序

O(n2)

O(n2)

O(1)


选择排序

O(n2)

O(n2)

O(1)

不是

直接插入排序

O(n2)

O(n2)

O(1)


希尔排序

O(nlogn)

O(ns)

O(1)

不是

归并排序

O(nlogn)

O(nlogn)

O(n)


快速排序

O(nlogn)

O(n2)

O(logn)

不是

一、冒泡排序
  • 时间复杂度最好的情况是已经排好序
  • 时间复杂度最好O(n),平均O(n2),最坏O(n2)
  • 空间复杂度O(1)
// 升序冒泡
public int [] bubbleSort(int [] arr){
    for(int i = 0; i < arr.length-1; i++){
        //定义一个标记,没有发生交换,则说明已经有序
        boolean flag = true;
        
        for(int j = 0; j < arr.length-i-1; j++){
            // 不断把大的数字往后交换
            if(arr[j] > arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
                flag = false;
            }
        }
        
        if(flag){
            break;
        }
    }
    return arr;
}
二、选择排序
  • 时间复杂度最好的情况是已经排好序
  • 时间复杂度最好O(n),平均O(n2),最坏O(n2)
  • 空间复杂度O(1)
// 升序简单选择排序
public int[]  selectSort(arr){
    for(int i = 0; i < arr.length-1; i++){
        // 每趟找最小的数
        min = i;
        for(int j = i+1; j < arr.length; j++){
            if(arr[j] < arr[min]){
                min = j;
            }
        }
        // 交换最小的数和下标为i的数
        int temp = arr[i];
        arr[i] = arr[min];
        arr[min] = temp;
    }
    return arr;
}
三、插入排序
  • 时间复杂度最好的情况是已经排好序
  • 时间复杂度最好O(n),平均O(n2),最坏O(n2)
  • 空间复杂度O(1)
public int [] insertSort(int [] nums){
    // i后面的数组表示待插入的数组
    for(int i = 1; i < nums.length; i++){
        // 记录要插入的数据
        int tmp = nums[i];
        // 边比较边移动
        int j = i;
        while(j > 0 && tmp < nums[j-1]){
            nums[j] = nums[j-1];
            j--;
        }
        // 插入
        if(j < i){
            nums[j] = tmp;
        }
    }
}
四、希尔排序

间隔步长step的数字归为一组,组内进行插入排序,step由大变小

  • 当增量序列为K = 2x时,时间复杂度为O(n2)
  • 当增量序列为K = (3 * x + 1)时,时间复杂度为O(n^3/2)
  • 空间复杂度为O(1)
public int [] shellSort(int [] nums) {
    // 每次增量都除以2
    for (int step = nums.length/2; step>0; step/=2) {
        // 每次都从step开始进行插入,直到数组末尾
        for (int i = step; i<nums.length; i++) {
            //内部和插入排序一样
            int j = i;
            int tmp = nums[i];
            while (j-step >= 0 && tmp < nums[j-step]) {
                nums[j] = nums[j-step];
                j = j-step;
            }
            if (j < i) {
                nums[j] = tmp;
            }
        }
    }
}
五、归并排序

原理如下:
对于给定的一组记录,利用递归与分治技术将数据序列划分成为越来越小的半子表,在对半子表排序,最后再用递归方法将排好序的半子表合并成为越来越大的有序序列


  • 时间复杂度最优、平均和最差都是O(nlogn)
  • 空间复杂度为:O(n)
public static void merge(int[] a, int low, int mid, int high) {
    int[] temp = new int[high - low + 1];
    int i = low;// 左指针
    int j = mid + 1;// 右指针
    int k = 0;
    // 把较小的数先移到新数组中
    while (i <= mid && j <= high) {
        if (a[i] < a[j]) {
            temp[k++] = a[i++];
        } else {
            temp[k++] = a[j++];
        }
    }
    // 把左边剩余的数移入数组
    while (i <= mid) {
        temp[k++] = a[i++];
    }
    // 把右边边剩余的数移入数组
    while (j <= high) {
        temp[k++] = a[j++];
    }
    // 把新数组中的数覆盖nums数组
    for (int k2 = 0; k2 < temp.length; k2++) {
        a[k2 + low] = temp[k2];
    }
}

public static void mergeSort(int[] a, int low, int high) {
    int mid = (low + high) / 2;
    if (low < high) {
        // 左边
        mergeSort(a, low, mid);
        // 右边
        mergeSort(a, mid + 1, high);
        // 左右归并
        merge(a, low, mid, high);
        System.out.println(Arrays.toString(a));
    }

}
六、快速排序
  • 最优情况是每次划分正好平分数组
  • 最差情况是每次划分落到最边缘,退化为冒泡排序
  • 时间复杂度最优O(nlogn),平均O(nlogn),最坏O(n^2)
  • 空间复杂度最优O(logn),平均O(logn),最差O(n)

排序实例

public static void sort(int a[], int low, int hight) {
    int i, j, index;
    if (low > hight) {
        return;
    }
    i = low;
    j = hight;
    index = a[i];       // 用子表的第一个记录做基准
    while (i < j) {     // 从表的两端交替向中间扫描
        while (i < j && a[j] >= index)
            j--;
        if (i < j)
            a[i++] = a[j];  // 用比基准小的记录替换低位记录
        while (i < j && a[i] < index)
            i++;
        if (i < j)   // 用比基准大的记录替换高位记录
            a[j--] = a[i];
    }
    a[i] = index;   // 将基准数值替换回 a[i]
    sort(a, low, i - 1);    // 对低子表进行递归排序
    sort(a, i + 1, hight); // 对高子表进行递归排序

}

public static void quickSort(int a[]) {
    sort(a, 0, a.length - 1);
}