常见的排序算法总结

2023-11-02

排序简介

简介

排序算法(英语:Sorting algorithm)是一种将一组特定的数据按某种顺序进行排列的算法。排序算法多种多样,性质也大多不同。

性质

稳定性

稳定性是指相等的元素经过排序之后相对顺序是否发生了改变。

拥有稳定性这一特性的算法会让原本有相等键值的记录维持相对次序,即如果一个排序算法是稳定的,当有两个相等键值的记录 R R R S S S ,且在原本的列表中 R R R 出现在 S S S 之前,在排序过的列表中 R R R 也将会是在 S S S 之前。

基数排序、计数排序、插入排序、冒泡排序、归并排序是稳定排序。

选择排序、堆排序、快速排序不是稳定排序。

时间复杂度

参考链接:复杂度

时间复杂度用来衡量一个算法的运行时间和输入规模的关系,通常用 O O O 表示。

简单计算复杂度的方法一般是统计“简单操作”的执行次数,有时候也可以直接数循环的层数来近似估计。

时间复杂度分为最优时间复杂度、平均时间复杂度和最坏时间复杂度。OI 竞赛中要考虑的一般是最坏时间复杂度,因为它代表的是算法运行水平的下界,在评测中不会出现更差的结果了。

基于比较的排序算法的时间复杂度下限是 O ( n l o g n ) O(nlogn) O(nlogn) 的。

当然也有不是 O ( n l o g n ) O(nlogn) O(nlogn) 的。例如,计数排序 的时间复杂度是 O ( n + w ) O(n+w) O(n+w) ,其中 w w w 代表输入数据的值域大小。

空间复杂度

与时间复杂度类似,空间复杂度用来描述算法空间消耗的规模。一般来说,空间复杂度越小,算法越好。

常见排序算法时空复杂度对比

常见排序算法时空复杂度对比

分类

常见算法可以分为两大类:

  • 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O ( n l o g n ) O(nlogn) O(nlogn) ,因此称为非线性时间比较类排序。
  • 线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。
    排序算法分类

外部链接

冒泡排序

简介

冒泡排序(英语:Bubble sort)是一种简单的排序算法。由于在算法的执行过程中,较小的元素像是气泡般慢慢「浮」到数列的顶端,故叫做冒泡排序。

工作原理

它的工作原理是每次检查相邻两个元素,如果前面的元素与后面的元素满足给定的排序条件,就将相邻两个元素交换。当没有相邻的元素需要交换时,排序就完成了。

经过 i i i 次扫描后,数列的末尾 i i i 项必然是最大的 i i i 项,因此冒泡排序最多需要扫描 n − 1 n-1 n1 遍数组就能完成排序。

性质

稳定性

冒泡排序是一种稳定的排序算法。

时间复杂度

在序列完全有序时,冒泡排序只需遍历一遍数组,不用执行任何交换操作,时间复杂度为 O ( n ) O(n) O(n)

在最坏情况下,冒泡排序要执行 ( n − 1 ) n 2 \frac{(n-1)n}{2} 2(n1)n 次交换操作,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

冒泡排序的平均时间复杂度为 O ( n 2 ) O(n^2) O(n2)

动图演示

冒泡排序

代码实现

C++

void swap(int &a, int &b) {
    if (a == b) return;
    // x ^ x = 0
    // x ^ 0 = x
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

void bubble_sort(int arr[], int n) {
    bool swaped = true;
    // 直到没有发生交换
    while (swaped) {
        swaped = false;
        for (int i = 0; i < n - 1; ++i) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                swaped = true;
            }
        }
        // 一轮冒泡确定一个最大值
        --n;
    }
}

选择排序

简介

选择排序(英语:Selection sort)是排序算法的一种,它的工作原理是每次找出第 i i i 小的元素(也就是 A i . . n A_i..n Ai..n 中最小的元素),然后将这个元素与数组第 i i i 个位置上的元素交换。

性质

稳定性

由于 swap(交换两个元素)操作的存在,选择排序是一种不稳定的排序算法。

时间复杂度

选择排序的最优时间复杂度、平均时间复杂度和最坏时间复杂度均为 O ( n 2 ) O(n^2) O(n2)

动图演示

选择排序

代码实现

C++

void swap(int &a, int &b) {
    if (a == b) return;
    // x ^ x = 0
    // x ^ 0 = x
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}


void selection_sort(int arr[], int n) {
    for (int i = 0; i < n; ++i) {
        int min_idx = i;
        for (int j = i + 1; j < n; ++j) {
            if (arr[j] < arr[min_idx]) {
                min_idx = j;
            }
        }
        swap(arr[i], arr[min_idx]);
    }
}

插入排序

简介

插入排序(英语:Insertion sort)是一种简单直观的排序算法。它的工作原理为将待排列元素划分为“已排序”和“未排序”两部分,每次从“未排序的”元素中选择一个插入到“已排序的”元素中的正确位置。

一个与插入排序相同的操作是打扑克牌时,从牌桌上抓一张牌,按牌面大小插到手牌后,再抓下一张牌。

性质

稳定性

插入排序是一种稳定的排序算法。

时间复杂度

插入排序的最优时间复杂度为 O ( n ) O(n) O(n) ,在数列几乎有序时效率很高。

插入排序的最坏时间复杂度和平均时间复杂度都为 O ( n 2 ) O(n^2) O(n2)

动图演示

插入排序

代码实现

C++

void insertion_sort(int arr[], int n) {
    for (int i = 1; i < n; ++i) {
        int cur = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > cur) {
            arr[j + 1] = arr[j];
            --j;
        }
        arr[j + 1] = cur;
    }
}

归并排序

简介

归并排序(英语:merge sort)是一种采用了 分治 思想的排序算法。

工作原理

归并排序分为三个步骤:

1. 将数列划分为两部分;
2. 将数列划分为两部分;
3. 合并两个子序列。

不难发现,归并排序的前两步都很好实现,关键是如何合并两个子序列。注意到两个子序列在第二步中已经保证了都是有序的了,第三步中实际上是想要把两个 有序 的序列合并起来。

性质

归并排序是一种稳定的排序算法。

归并排序的最优时间复杂度、平均时间复杂度和最坏时间复杂度均为 O ( n l o g n ) O(nlogn) O(nlogn)

归并排序的空间复杂度为 O ( n ) O(n) O(n)

动图演示

归并排序

代码实现

C++

int tmp_arr[MAX_N];

void merge_sort(int arr[], int l, int r) {

    if (l >= r) return;

    int mid = (l + r) >> 1;

    merge_sort(arr, l, mid);
    merge_sort(arr, mid + 1, r);

    // 至此,数组两边均有序

    int k = 0, i = l, j = mid + 1;

    // 合并
    while (i <= mid && j <= r) {
        if (arr[i] <= arr[j])
            tmp_arr[k++] = arr[i++];
        else
            tmp_arr[k++] = arr[j++];
    }
    // 处理剩下的
    while (i <= mid)
        tmp_arr[k++] = arr[i++];
    while (j <= r)
        tmp_arr[k++] = arr[j++];
    // 将数据复制回原数组
    for (i = l, j = 0; i <= r; i++, j++)
        arr[i] = tmp_arr[j];
}

逆序对

归并排序还可以用来求逆序对的个数。

所谓逆序对,就是满足 a i > a j a_i>a_j ai>aj i < j i<j i<j 的数对 ( i , j ) (i,j) (i,j)

代码实现

C++

int tmp_arr[MAX_N];

long long merge_sort(int arr[], int l, int r) {

    if (l == r) return 0;

    int mid = (l + r) >> 1;

    long long ans = merge_sort(arr, l, mid) + merge_sort(arr, mid + 1, r);

    int i = l, j = mid + 1, k = 0;

    while (i <= mid && j <= r) {
        if (arr[i] <= arr[j])
            tmp_arr[k++] = arr[i++];
        else {
            ans += mid - i + 1;
            tmp_arr[k++] = arr[j++];
        }
    }

    while (i <= mid)
        tmp_arr[k++] = arr[i++];

    while (j <= r)
        tmp_arr[k++] = arr[j++];

    for (i = l, j = 0; i <= r; ++i, ++j)
        arr[i] = tmp_arr[j];

    return ans;
}

另外,逆序对也可以用 树状数组、线段树 等数据结构求解。这三种方法的时间复杂度都是 O ( n l o g n ) O(nlogn) O(nlogn)

外部链接

Merge Sort - GeeksforGeeks
归并排序 - 维基百科,自由的百科全书
逆序对 - 维基百科,自由的百科全书

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常见的排序算法总结 的相关文章

随机推荐

  • 回顾:HTTP/HTTPS/对称加密/非对称加密/session/cookie/token

    HTTP超文本传输协议 通过浏览器和服务器进行数据交互 进行超文本 文字 图片 视频等 传输的规定 规定了超文本传输要遵守的规则 特点 1 HTTP协议是无状态的 每次HTTP请求都是独立的 任何两个请求之间没有必然的联系 当然实际应用种并
  • Docker中安装Jenkins

    本篇主要讲如何在Docker中安装Jenkins 如果Docker未安装 可以先参考上一篇文章进行Docker安装 学习Docker 一 centos系统 Docker 安装与卸载 安装 拉取镜像 docker pull jenkins j
  • 关于Qt控制中边框的显示的一些设置(完善中)

    1 可以通过指定类型来选择一类控件进行设置 QLineEdit background color rgb 255 255 255 border radius 8px border color rgb 0 0 0 border style s
  • Linux中more命令的使用,Linux中more命令使用详解教程

    1 使用权限 所有者 什么是所有者权限 2 使用方式more 参数选项 文件 参数 num 从第num行开始显示 num 定义屏幕大小 为num行 pattern 从pattern 前两行开始显示 c 从顶部清屏然后显示 d 提示Press
  • 如何用 Python 开发一个简单的 blender 插件

    Blender是一款开源的3D建模和动画制作软件 支持Python脚本编写插件 下面是一个简单的Blender插件开发示例 首先 需要安装Blender软件 并确保安装了Python库 可以在Blender软件安装目录下的Python目录中
  • Windows安装Mysql(免安装版)

    Windows安装Mysql8 0 25教程 免安装版 1 下载mysql Mysql官网下载地址 2 配置初始化文件my ini 在根目录 与bin目录同级 下创建my txt文件 将以下内容复制到该文件中 其中mysql的安装目录和数据
  • 想将PPT的文字转换到Word文档?看这一篇就够了!!!

    将PPT的文字转换到Word文档 又到了期末考试复习周呢 一些老师会给我们复习的PPT 为了方便 我们当然会选择把它打印出来 但是看到这么多页的PPT 比如下面这张图就是我们老师给的PPT 我简直震惊 于是开始探索将PPT转化为Word的方
  • 【C++自我精讲】基础系列五 隐式转换和显示转换

    C 自我精讲 基础系列五 隐式转换和显示转换 前言 1 C 的类型转换分为两种 一种为隐式转换 另一种为显式转换 2 C 中应该尽量不要使用转换 尽量使用显式转换来代替隐式转换 1 隐式转换 定义 隐式转换是系统跟据程序的需要而自动转换的
  • 从零到独自开发一个网站(后端)

    从零到独自开发一个网站 后端 2015 09 15 16 22 25 本博客采用创作共用版权协议 要求署名 非商业用途和保持一致 转载本博客文章必须也遵循署名 非商业用途 保持一致的创作共用协议 折腾了9个小时终于把服务器架好了 因为uws
  • Altium designer(21) PCB除选中层,其它层变灰色,如何变回正常模式

    如下图所示 AD21软件 在PCB画图时 当前在TOP layer 其他层全部变成灰色了 看起来有些奇怪 原因 此时选择的应该是single layer mode 将这个模式关闭即可 步骤 右下角 panels gt view config
  • 从数据类型 varchar 转换为 numeric 时出错.

    如果说你的数据库字段是varchar 但是存储的数据是数值 在出报表时需要转成int或numeric时 无论怎么样都报错 错误信息 消息 8114 级别 16 状态 5 第 1 行 从数据类型 varchar 转换为 numeric 时出错
  • java基础知识

    java基础知识 1 常见的数据源 dbcp 半自动化操作 不能自己连接 c3p0 自动化操作 自动加载配置文件 并且自动配置设置到对象中 druid hikari 2 url pattern配置为 和 的区别 首先 可以匹配所有url 包
  • [1109]Maven全局配置文件settings.xml详解

    文章目录 一 概要 1 settings xml的作用 2 settings xml文件位置 3 配置的优先级 二 settings xml元素详解 1 顶级元素概览 1 1 LocalRepository 1 2 InteractiveM
  • Livox 学术小课堂|基于高精度反射率的建图色彩优化

    武汉大学VaST 课题组的王昱升博士最近分享了他们在轨道交通场景下利用Livox 激光雷达进行建图 并基于高精度反射率对点云图进行色彩优化 辅助轨道交通语义地图构建的工作 实测场景及点云图 项目组计划通过自研SLAM算法针对大场景铁路环境进
  • anconda配置环境变量

    1 将anconda安装根目录添加进环境变量path中 2 将anconda根目录下的Scripts路径添加进环境变量path中 这样就可以在cmd中打开notebook了 如图
  • Python中tkFileDialog实现文件选择、保存和路径选择

    tkFileDialog文件选择 保存和路径选择 概述 示例 概述 看了下Tkinter的文档 对于Pop up dialog有三类 现在用到的是tkFileDialog tkFileDialog有三种形式 一个是 askopenfilen
  • 解决跨域的配置

    这里写自定义目录标题 解决跨域问题 解决跨域问题 在网关中添加跨域的配置文件 Configuration public class MymallCorsConfiguration Bean public CorsWebFilter cors
  • 开源项目选型考虑的四个方面

    http www trinea cn other open source choice
  • 基于多视角学习和个性化注意力机制的新闻推荐

    NPA Neural News Recommendation with Personalized Attention 2019 7 链接 https arxiv org abs 1907 05559 发表在 IJCAI 2019和 KDD
  • 常见的排序算法总结

    排序简介 简介 排序算法 英语 Sorting algorithm 是一种将一组特定的数据按某种顺序进行排列的算法 排序算法多种多样 性质也大多不同 性质 稳定性 稳定性是指相等的元素经过排序之后相对顺序是否发生了改变 拥有稳定性这一特性的