排序算法

110 阅读3分钟

排序算法

算法分类

比较类排序: 通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),也被称为非线性时间比较类排序
非比较类排序: 不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,也被称为线性时间非比较类排序
排序算法 比较类排序 交换排序 冒泡排序
快速排序
插入排序 简单插入排序
希尔排序
选择排序 简单选择排序
堆排序
归并排序 二路归并排序
多路归并排序
非比较排序 计数排序
桶排序
基数排序

算法复杂度

排序方法时间复杂度(平均)时间复杂度(最坏)时间复杂度(最好)空间复杂度稳定性
插入排序O(n²)O(n²)O(n)O(1)稳定
希尔排序O(n¹•³)O(n²)O(n)O(1)不稳定
选择排序O(n²)O(n²)O(n²)O(1)不稳定
堆排序O(nlog₂n)O(nlog₂n)O(nlog₂n)O(1)不稳定
冒泡排序O(n²)O(n²)O(n)O(1)稳定
快速排序O(nlog₂n)O(n²)O(nlog₂n)O(nlog₂n)不稳定
归并排序O(nlog₂n)O(nlog₂n)O(nlog₂n)O(n)稳定
计数排序O(n+k)O(n+k)O(n+k)O(n+k)稳定
桶排序O(n+k)O(n²)O(n)O(n+k)稳定
基数排序O(n*k)O(n*k)O(n*k)O(n+k)稳定

相关概念

稳定: 若a原本在b前面,而a=b,排序后a仍在b前面
不稳定: 若a原本在b前面,而a=b,排序后a可能出现在b后面
时间复杂度: 对排序数据的总的操作次数
空间复杂度: 指算法在计算机内执行时所需存储空间的度量,也是数据规模的函数

冒泡排序

依次比较相邻的两个元素,左边的元素若比右边的大,就将它俩的位置相互调换

动画演示

冒泡排序

代码实现

public static List<Integer> bubbleSort(Integer... i) {

    /* 临时变量 */
    int snap;

    /* 冒泡次数,排除排序可能出现的错误 */
    for (int j = 0; j < i.length; j++) {
        /* 冒泡排序 */
        for (int l = 0; l < i.length - 1; l++) {
            /* 与后一个数字比较大小,若这个数字大于下一个数字则将二者的顺序进行调换 */
            if (i[l] > i[l + 1]) {
                snap = i[l];
                i[l] = i[l + 1];
                i[l + 1] = snap;
            }
        }
    }

    return Arrays.asList(i);

}

选择排序

依次将从待排序的数组中选出最小的元素,将其放置到待排序的数组中的最左边

动画演示

选择排序

代码实现

public static List<Integer> selectSort(Integer... i) {

    int snap,
            t /* 临时变量 */;

    for (int j = 0; j < i.length; j++) {

        /* 记录数组中最小值的下标 */
        snap = j;

        for (int l = snap + 1; l < i.length; l++)
            /* 判断当前最小值是否大于后续值,若大于就将最小值的索引赋值给临时变量 */
            if (i[snap] > i[l]) snap = l;

        t = i[j];
        i[j] = i[snap];
        i[snap] = t;

    }

    return Arrays.asList(i);

}

快速排序

通过定位基准元素将待排序数组分成两部分,比关键字小和比关键字大的,再将这两部分通过递归达到有序排序的效果

动画演示

快速排序

代码实现

public static List<Integer> quickSort(Integer[] i) {

    quickSort(i, 0, i.length - 1);

    return Arrays.asList(i);

}

private static void quickSort(Integer[] i, Integer start, Integer end) {

	/* 当条件不满足时,跳出程序,避免堆栈溢出 */
    if (start > end) return;

    /* 变量定义 */
    int datum = i[start],
            j = start,
            l = end,
            temporary;

    while (j < l) {

        /* 获取比基准元素小的元素在数组中的索引 */
        while (datum <= i[l] && j < l) l--;

        /* 获取比基准元素大的元素在数组中的索引 */
        while (datum >= i[j] && j < l) j++;

        if (j < l) {
            temporary = i[l];
            i[l] = i[j];
            i[j] = temporary;
        }
    }

    /* 将基准元素与j、k相等的索引处的数字交换 */
    i[start] = i[j];
    i[j] = datum;

    /* 递归调用当前基准元素左边的数组 */
    quickSort(i, start, j - 1);
    /* 递归调用当前基准元素右边的数组 */
    quickSort(i, j + 1, end);

}

插入排序

从数组的索引1开始,将数组中待排序的元素按照升序规则插入到已排序好的数组中

动画实现

插入排序

代码实现

public static List<Integer> insertionSort(Integer... i) {

    /* 临时变量 */
    int temporary;

    /* 从索引1处循环整个数组 */
    for (int j = 1; j < i.length; j++) {
        /* 倒序循环已排序的数组 */
        for (int l = j; l > 0; l--) {
            /* 与已排序的数组元素进行对比,当前元素小于上一个元素,就与其进行位置调换 */
            if (i[l] < i[l - 1]) {
                temporary = i[l];
                i[l] = i[l - 1];
                i[l - 1] = temporary;
            }
        }
    }

    return Arrays.asList(i);

}

以下仅为动画演示,暂未进行研究

计数排序

动画演示

计数排序

代码实现

在这里插入代码片

基数排序

动画演示

基数排序

代码实现

在这里插入代码片

归并排序

动画演示

归并排序

代码实现

在这里插入代码片

堆排序

动画演示

堆排序

代码实现

在这里插入代码片