常见的排序算法分析

简介: 排序是将一组数据元素序列重新排列,使得数据元素序列按某个数据项(关键字)有序。不管是在数据处理中,还是别的应用场景中,对数据的排序都是很有必要的。对于任意的数据元素序列,若排序前后所有相同关键字的相对位置不变,则称该排序算法为稳定的排序方法,否则为不稳定的排序方法。例如对下面数据做排序操作:3, 2, 3, 4 -> 2, 3, 3, 4带下划线的3的位置发生了变化,则该排序方法是不稳定的。


一、概述



排序是将一组数据元素序列重新排列,使得数据元素序列按某个数据项(关键字)有序。不管是在数据处理中,还是别的应用场景中,对数据的排序都是很有必要的。对于任意的数据元素序列,若排序前后所有相同关键字的相对位置不变,则称该排序算法为稳定的排序方法,否则为不稳定的排序方法。例如对下面数据做排序操作:

3, 2, 3, 4   ->   2, 3, 3, 4

带下划线的3的位置发生了变化,则该排序方法是不稳定的。


二、冒泡排序



冒泡排序是将相邻两个关键字对比,若为 a1>a2 则进行交换,然后依次比较后面的数据,直到最后,每一趟冒泡排序,都会确定最大的关键字记录并放至最后。假设我们有一组数据 4,6,3,5,1,2,对它进行冒泡排序过程如下:

微信图片1111.png

微信图片11111.gif

算法实现代码如下:

public static int[] bubbleSort(int[] a) {
    for (int i = 0; i < a.length - 1; i++) {
        for (int j = 0; j < a.length - i - 1; j++) {
            if (a[j] > a[j + 1]) {
                int tmp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = tmp;
            }
        }
    }
    return a;
}

根据上面代码可以计算出时间复杂度如下:

(n-1) + (n-2) + ...  + (n-i) + ...  + 1 = n(n-1)/2

所以时间复杂度为 O(n^2),只使用一个临时变量,空间复杂度为 O(1)


三、选择排序



选择排序是从无序的序列中选择关键字最小或最大的记录,并将它加入到有序的子序列中,如果我们每次选择最小的记录,每进行一趟排序,就会确定最小的关键字并放至最前。假设我们有一组数据 4,6,3,5,1,2,对它进行选择排序过程如下:微信图片2222.png

微信图片22222.gif算法实现代码如下:

public static int[] selectSort(int[] a) {
    for (int i = 0; i < a.length - 1; i++) {
        for (int j = i + 1; j < a.length; j++) {
            if (a[i] > a[j]) {
                int tmp = a[j];
                a[j] = a[i];
                a[i] = tmp;
            }
        }
    }
    return a;
}

根据上面代码可以计算出时间复杂度如下:

(n-1) + (n-2) + ...  + (n-i) + ...  + 1 = n(n-1)/2

所以时间复杂度为 O(n^2),只使用一个临时变量,空间复杂度为 O(1)


四、插入排序



插入排序是将无序的数据序列中的一个或几个记录插入到有序子序列中,从而增加有序子序列的长度。每一趟排序都会确定最小的关键字并放至最前。假设我们有一组数据 4,6,3,5,1,2,对它进行插入排序过程如下:

微信图片3333.png

微信图片33333.gif

算法实现代码如下:

public static int[] insertSort(int[] a) {
    int tmp;
    for (int i = 1; i < a.length; i++) {
        int j = i - 1;
        tmp = a[i];
        for (; j >= 0 && tmp < a[j]; j--) {
            a[j + 1] = a[j];
        }
        a[j + 1] = tmp;
    }
    return a;
}

根据上面代码可以计算出时间复杂度如下:

n + (n-1) + (n-2) + ...  + (n-i) + ...  + 2 = (n+2)(n-1)/2

所以时间复杂度为 O(n^2),只使用一个临时变量,空间复杂度为 O(1)


五、归并排序



归并排序是将两个或两个以上的有序表组合成一个新的有序表,我们在进行归并排序时会将数据元素序列,按照 n/2 的长度递归拆分,然后再两两合并,每一个合并的操作都只是对于两个有序表进行合并,直至得到一个长度为 n 的有序序列为止。假设我们有一组数据 4,6,3,5,1,2,对它进行归并排序过程如下:

微信图片4444.png

微信图片44444.gif

算法实现代码如下:

public static int[] mergeSort(int[] a, int l, int r) {
    if (l < r) {
        int m = (l + r) / 2;
        mergeSort(a, l, m);
        mergeSort(a, m + 1, r);
        merge(a, l, m, r);
    }
    return a;
}
private static void merge(int[] a, int l, int m, int r) {
    int n1 = m - l + 1;
    int n2 = r - m;
    int[] L = new int[n1];
    int[] R = new int[n2];
    System.arraycopy(a, l, L, 0, n1);
    System.arraycopy(a, m + 1, R, 0, n2);
    int i = 0, j = 0, k = l;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            a[k++] = L[i++];
        } else {
            a[k++] = R[j++];
        }
    }
    while (i < n1) {
        a[k++] = L[i++];
    }
    while (j < n2) {
        a[k++] = R[j++];
    }
}

根据上面代码可以得出,每一趟归并的时间复杂度为 O(n),总共需要归并 log2n 趟,因而总的时间复杂度为 O(n*log n),在归并的过程中,需要一个与数据表等长的数组空间,因此,空间复杂度为 O(n)


六、快速排序



快速排序是实际使用中已知的最快的算法,快速排序在数据元素中选择一个数据元素为枢纽,然后把比它小的放前面,比它大的放后面,这样分成两堆,然后对两个小堆做同样的操作,以此类推,直到不能分为止,最后返回最终排序结果,快速排序的设计,关键在于枢纽的选择。假设我们有一组数据 4,6,3,5,1,2,选择第一个关键字作为枢纽,对它进行快速排序过程如下:

微信图片5555.png

微信图片55555.gif

算法实现代码如下:

public static int[] quicklySort(int[] a, int l, int r) {
    if (l >= r) {
        return a;
    }
    int i = l, j = r, k = a[l];
    while (i != j) {
        while (i < j && a[j] > k) {
            j--;
        }
        a[i] = a[j];
        while (i < j && a[i] <= k) {
            i++;
        }
        a[j] = a[i];
        a[i] = k;
    }
    quicklySort(a, l, j - 1);
    quicklySort(a, j + 1, r);
    return a;
}

如果每次总是选到中间值作为枢纽,那快速排序可以达到最好的情况,时间复杂度为 O(n*log n),如果每次总是选到最小或最大值作为枢纽,最坏情况时间复杂度为 O(n^2)。对应的空间复杂度最坏情况为 O(n),平均情况为 O(log n)

读者可以去网上找资料,了解快速排序中确定枢纽位置的相关算法。

七、总结



五种排序算法对比

算法 冒泡排序 选择排序 插入排序 归并排序 快速排序
稳定性 稳定 不稳定 稳定 稳定 不稳定
平均时间复杂度 O(n^2) O(n^2) O(n^2) O(n*log n) O(n*log n)
最坏时间复杂度 O(n^2) O(n^2) O(n^2) O(n*log n) O(n^2)
空间复杂度 O(1) O(1) O(1)


递归与分治策略


前面讲到的归并排序和快速排序,都使用到了分治策略,为了解决一个规模较大的问题,我们可以将其分解成两个子问题,并借助递归分别得到它们的解,然后将子问题的解合并成原问题的解,这就是分治策略。我们把一个规模大的问题,分解成 k 个子问题,对这 k 个子问题分别求解,如果子问题的规模仍然不够小,则再划分为 k 个子问题,如此递归的进行下去,直到问题的规模足够小,很容易求出其解为止。微信图片6666.png

目录
相关文章
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
339 3
|
1月前
|
运维 监控 JavaScript
基于 Node.js 图结构的局域网设备拓扑分析算法在局域网内监控软件中的应用研究
本文探讨图结构在局域网监控系统中的应用,通过Node.js实现设备拓扑建模、路径分析与故障定位,提升网络可视化、可追溯性与运维效率,结合模拟实验验证其高效性与准确性。
167 3
|
4月前
|
机器学习/深度学习 边缘计算 算法
NOMA和OFDMA优化算法分析
NOMA和OFDMA优化算法分析
264 127
|
6月前
|
数据采集 机器学习/深度学习 算法
别急着上算法,咱先把数据整明白:大数据分析的5个基本步骤,你都搞对了吗?
别急着上算法,咱先把数据整明白:大数据分析的5个基本步骤,你都搞对了吗?
357 4
|
29天前
|
存储 边缘计算 算法
【太阳能学报EI复现】基于粒子群优化算法的风-水电联合优化运行分析(Matlab代码实现)
【太阳能学报EI复现】基于粒子群优化算法的风-水电联合优化运行分析(Matlab代码实现)
|
2月前
|
机器学习/深度学习 算法 5G
【MUSIC、最大似然与克拉美-罗下界】MUSIC与ESPRIT 算法来估计到达角(AoA),并尝试推导克拉美-罗下界(CRLB)以分析其性能研究(Matlab代码实现)
【MUSIC、最大似然与克拉美-罗下界】MUSIC与ESPRIT 算法来估计到达角(AoA),并尝试推导克拉美-罗下界(CRLB)以分析其性能研究(Matlab代码实现)
118 0
|
3月前
|
编解码 算法 5G
MIMO雷达空间谱估计中Capon算法与MUSIC算法的对比分析及实现
MIMO雷达空间谱估计中Capon算法与MUSIC算法的对比分析及实现
250 2
|
3月前
|
人工智能 自然语言处理 算法
2025 年 7 月境内深度合成服务算法备案情况分析报告
2025年7月,中央网信办发布第十二批深度合成算法备案信息,全国389款产品通过备案,服务提供者占比超七成。截至7月14日,全国累计备案达3834款,覆盖文本、图像、音视频等多模态场景,广泛应用于生活服务、医疗、金融等领域。广东以135款居首,数字人、AI客服等C端应用主导,民营企业成主力,国企聚焦公共服务。随着AI政策推动,备案已成为AI产品合规上线关键环节。
|
6月前
|
存储 监控 算法
员工行为监控软件中的 Go 语言哈希表算法:理论、实现与分析
当代企业管理体系中,员工行为监控软件已逐步成为维护企业信息安全、提升工作效能的关键工具。这类软件能够实时记录员工操作行为,为企业管理者提供数据驱动的决策依据。其核心支撑技术在于数据结构与算法的精妙运用。本文聚焦于 Go 语言中的哈希表算法,深入探究其在员工行为监控软件中的应用逻辑与实现机制。
159 14
|
7月前
|
自然语言处理 算法 安全
境内深度合成服务算法备案通过名单分析报告
本报告基于《境内深度合成服务算法备案通过名单》,分析了2023年6月至2025年3月公布的10批备案数据,涵盖属地分布、行业应用及产品形式等多个维度。报告显示,深度合成算法主要集中于经济发达地区,如北京、广东、上海等地,涉及教育、医疗、金融、娱乐等多行业。未来趋势显示技术将向多模态融合、行业定制化和安全合规方向发展。建议企业加强技术研发、拓展应用场景、关注政策动态,以在深度合成领域抢占先机。此分析旨在为企业提供参考,助力把握技术发展机遇。
境内深度合成服务算法备案通过名单分析报告

热门文章

最新文章