【数据结构】排序(直接插入、折半插入、希尔、冒泡、快速、直接选择、堆、归并、基数排序)

2023-11-18

一、什么是排序

排序:将一组杂乱无章的数据按一定规律顺次排列起来。即,将无序序列的数据节点包含多个数据域,那么排序往往是针对其中某个域而言。

二、排序方法的分类

 1.按数据存储介质可分为:

内部排序:数据量不大、数据在内存,无需内外存交换数据

外部排序:数据量较大、数据在外存(文件排序)。外部排序时,要将数据分批调入内存来排序,中间结果还要及时放入外存,显然外部排序要复杂的多。

2.按比较器个数可分为:

串行排序:单处理机(同一时刻比较一对元素)

并行排序:多处理机(同一时刻比较多对元素)

3.按主要操作可分为:

比较排序:用比较的方法。  插入排序、交换排序、选择排序、归并排序

基数排序:不比较元素的大小,仅仅根据元素本身的取值确定其有序位置

4.按辅助空间可分为:

原地排序:辅助空间用量为O(1)的排序方法。(所占的辅助存储空间与参加排序的数据量大小无关)

非原地排序:辅助空间用量超过O(1)的排序方法。

5.按稳定性可分为:

稳定排序:能够使任何数值相等的元素,排序以后相对次序不变

非稳定性排序:不是稳定排序的方法

排序的稳定性只对结构类型数据排序有意义

排序方法是否稳定,并不能衡量一个排序算法的优劣。

6.按自然性可分为:

自然排序:输入数据越有序,排序的速度越快的排序方法

非自然排序:不是自然排序的方法

三、排序类型

插入排序

基本思想:每步将一个待排序的对象,按其关键码大小,插入前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。

即边插入边排序,保证子序列中随时都是排好序的。

 在插入a[i]前,数组a的前半段(a[0]~a[i-1])是有序段,后半段(a[i]~a[n-1])是停留于输入次序的“无序段”。

插入a[i]使a[0]~a[i-1]有序,也就是要为a[i]找到有序位置j(0<=j<=i),将a[i]插入在a[j]的位置上。

 直接插入排序

每次插入数据时都要比较两次,判断下标是否越界,因此为了减少一次比较次数,加入“哨兵”,将索引为0的位置赋值为要加入的数据的值。

 

 直接插入排序------性能分析

实现排序的基本操作有两个:

(1)“比较”序列中两个关键字的大小

(2)“移动”记录

最好的情况(关键字在记录序列中顺序有序

“比较的次数”:\sum_{i=2}^{n}=n-1      “移动”的次数:0

最坏的情况(关键字在记录系列中逆序有序

“比较的次数”:\sum_{i=2}^{n}=\frac{(n+2)(n-1)}{2}   “移动”的次数:\sum_{i=2}^{n}(i+1)=\frac{(n+4)(n-1)}{2}

 平均的情况

“比较”的次数\sum_{i=1}^{n-1}\frac{i+1}{2}=\frac{1}{4}(n+2)(n-1)

“移动”的次数:\sum_{i=1}^{n-1}(\frac{i+1}{2}+1)=\frac{1}{4}(n+6)(n-1)

时间复杂度:

 折半插入排序

 折半插入排序------算法分析

折半查找比顺序查找快,所以折半插入排序就平均性能来说比直接插入排序要快;

它所需要的关键码比较次数与待排序对象序列的初始排列无关,仅依赖于对象个数。在插入第i个对象时,需要经过log2^{i}+1次关键码比较,才能确定它插入的位置;

  当n较大时,总关键码比较次数比直接插入排序的最坏情况要好得多,但比其最好情况要差;

  在对象的初始排列已经按关键码排好序或接近有序时,直接插入排序比折半插入排序执行的关键码比较次数要少;

 折半插入排序的对象移动次数与直接插入排序相同,依赖于对象的初始排列

     减少了比较次数,但没有减少移动次数

     平均性能优于直接插入排序

时间复杂度为O(n^2)

空间复杂度为O(1)

是一种稳定的排序方法

希尔排序(Shell Sort)

 基本思想:先将整个待排记录序列分割成若干个子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

希尔排序算法,特点:

(1)缩小增量

(2)多遍插入排序

 希尔排序特点:

一次移动,移动位置较大,跳跃式地接近排序后的最终位置

最后一次只需要少量移动

增量序列必须是递减的,最后一个必须是1

增量序列应该是互质的

希尔排序算法分析

希尔排序法是一种不稳定的排序算法 

 交换排序

基本思想:两两比较,如果发生逆序则交换,直到所有记录都排好序为止。

常见的交换排序方法:冒泡排序、快速排序

 冒泡排序

 

 优点:每趟结束,不仅能挤出一个最大值到最后面位置,还能同时部分理顺其他元素;

一旦某一趟比较时不出现记录交换,说明已经排好序了,就可以结束本算法。

 设置一个标记位flag,如果发生交换,flag=1;若本趟没发生交换,flag保持为0

冒泡排序算法分析

  最好情况(正序)

        比较次数:n-1    

        移动次数:0

  最坏情况(逆序)

        比较次数:\sum_{i=1}^{n-1}=\frac{1}{2}(n^{2}-n)

        移动次数:3\sum_{i=1}^{n}(n-i)=\frac{3}{2}(n^{2}-n)

冒泡排序最好时间复杂度是O(n)

冒泡排序最坏时间复杂度是O(n^2)

冒泡排序最好时间复杂度是O(n^2)

冒泡排序算法中增加一个辅助空间temp,辅助空间为S(n)=O(1)

冒泡排序是稳定的

快速排序

------改进的交换排序

基本思想:任取一个元素(如:第一个)为中心(pivot:枢轴、中心点);

                  所有比它小的元素一律前放,比它大的元素一律后放,形成左右两个子表;

                  对各子表重新选择中心元素并依此规则调整(递归思想);

                 直到每个子表的元素只剩一个。

快速排序

基本思想:通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录进行排序,以达到整个序列有序。

具体实现:选定一个中间数作为参考,所有元素与之比较,小的调到其左边,大的调到其右边。

(枢轴)中间数:可以是第一个数、最后一个数、最中间一个数、任选一个数等。

 每一趟的子表的形成是采用从两头向中间交替式逼近法;

由于每趟中对各子表的操作都相似,可采用递归算法。

 快速排序算法分析:

时间复杂度:

  可以证明,平均计算时间是O(nlog2^{n})。

        Qsort():O(log2^{n})

        Partition():O(n) 

实验结果表明:就平均计算时间而言,快速排序是我们所讨论的所有内排序方法中最好的一个。

 空间复杂度:

快速排序不是原地排序

由于程序中使用了递归,需要递归调用栈的支持,而栈的长度取决于递归调用的深度。(即使不用递归,也需要用用户栈)

在平均情况下:需要O(logn)的栈空间

最坏情况下:栈空间可达O(n)

快速排序是一种不稳定的排序方法

快速排序不适于对原本有序或基本有序的记录序列进行排序

划分元素的选取是影响时间性能的关键;

输入数据次序越乱,所划分元素值的随机性越好,排序速度越快,快速排序不是自然排序方法;

改变划分元素的选取方法,至多只能改变算法平均情况下的时间性能,无法改变最坏情况下的时间性能。即最坏情况下,快速排序的时间复杂性总是O(n^{2})。

选择排序

简单选择排序

基本思想:在待排序的数据中选出最大(小)的元素放在其最终的位置。

基本操作:

1.首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换;

2.再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换;

3.重复上诉操作,共进行n-1趟排序后,排序结束。

 

 简单选择排序算法分析

时间复杂度:

        记录移动次数:

                最好情况:0

                最坏情况:3(n-1)

        比较次数:无论待排序列处于什么状态,选择排序所需要进行的“比较”次数相同。

                        \sum_{i=1}^{n-1}(n-i)=\frac{n}{2}(n-1)

简单选择排序是不稳定排序

堆排序

 若在输出堆顶的最小值(最大值)后,使得剩余n-1个元素的序列重新又建成一个堆,则得到n个元素的次小值(次大值).......如此反复,便能得到一个有序序列,这个过程称之为堆排序。

实现堆排序需要解决两个问题:

1.如何由一个无序序列建成一个堆?

2.如何在输出堆顶元素后,调整剩余元素为一个新的堆?

解决问题2:堆的调整

(1)输出堆顶元素之后,以堆中最后一个元素替代之;

(2)然后将根结点值与左、右子树的根结点值进行比较,并与其中小(大)者进行交换;

(3)重复上述操作,直至叶子结点,将得到新的堆,称这个从堆顶至叶子的调整过程为“筛选”。

 可以看出:对一个无序序列反复“筛选”就可以得到一个堆;即:从一个无序序列建堆的过程就是一个反复“筛选”的过程。

解决问题1:堆的建立

        很显然,单结点的二叉树是堆;

        在完全二叉树中所有以叶子结点(序号i>n/2)为根的子树是堆。

        这样,我们只需依次将以序号为n/2,n/2-1,.....,1的结点为根的子树调整为堆即可。

        即:对应由n个元素组成的无序序列,“筛选”只需从第n/2个元素开始。

 由以上分析可知:        

        若对一个无序序列建堆,然后输出根;重复该过程就可以由一个无序序列输出为有序序列。

        实质上,堆排序就是利用完全二叉树中父结点与孩子结点之间的内在关系来排序的。

 算法性能分析:

         堆排序的时间主要耗费在建初始堆和调整建新堆时进行反复“筛选”上。堆排序在最坏情况下,其时间复杂度也为0(nlog2^{n}),这是堆排序的最大优点。无论待排序列中的记录是正序还是逆序排列,都不会时堆排序处于“最好”或“最坏”的状态。

        另外,堆排序仅需一个记录大小供交换用的辅助存储空间。

        然而堆排序是一种不稳定的排序方法,它不适用于待排序记录个数n较少的情况,但对n较大的文件还是很有效的。

归并排序

基本思想:将两个或两个以上的有序子序列“归并”为一个有序序列。

在内部排序中,通常采用的是2-路归并排序。即:将两个位置相邻的有序子序列R[/...m]和R[m+1...n]归并为一个有序序列R[/...n]

 两两比较大小

 算法分析:

时间效率:O(nlog2n)

空间效率:O(n)

        因为需要一个与原始序列同样大小的辅助序列(R1)。这正是此算法的缺点

稳定性:稳定

基数排序

基本思想:分配+收集

        也叫桶排序或箱排序:设置若干个箱子,将关键字为k的记录放入第k个箱子,然后再按序号将非空的连接。

基数排序:数字是有范围的,均由0-9这十个数字组成,则只需设置十个箱子,相继按个、十、百...进行排序。

 基数排序算法分析:

时间效率:O(k*(n+m))    k:关键字个数,m:关键字取值范围为m个值

空间效率:O(n+m)

稳定性:稳定 

 四、排序类型比较

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

【数据结构】排序(直接插入、折半插入、希尔、冒泡、快速、直接选择、堆、归并、基数排序) 的相关文章

随机推荐

  • 20个简洁的 JS 代码片段

    20个简洁的 JS 代码片段 1 单行 If Else 语句 这是许多编程语言的共同特征 你可以使用三元运算符用一行代码编写整个语句 而不是在多行上编写 if else 例如 const age 12 let ageGroup LONG F
  • proteus8.9仿真闪退怎么解决?如何找到ProgramData?

    proteus8 9仿真闪退 将C Program Files x86 Labcenter Electronics Proteus 8 Professional 中MODELS文件夹复制到C ProgramData Labcenter El
  • 线性代数---之正交向量

    转载 百度百科 正交向量 编辑 本词条由 科普中国 百科科学词条编写与应用工作项目审核 正交向量 是一个数学术语 指点积为零的两个或多个向量 几何向量的概念在 线性代数中经由抽象化 得到更一般的向量概念 此处向量定义为 向量空间的元素 要注
  • 【计算机视觉

    文章目录 一 检测相关 11篇 1 1 Follow Anything Open set detection tracking and following in real time 1 2 YOLO MS Rethinking Multi
  • 【分治法】中位数问题和Gray码问题——武汉理工大学算法分析与设计课程实验

    i 中位数问题 问题描述 设X 0 n 1 和Y 0 n 1 为两个数组 每个数组中含有n个已排好序的数 找出X和Y的2n个数的中位数 编程任务 利用分治策略试设计一个O log n 时间的算法求出这2n个数的中位数 数据输入 由文件inp
  • sublime text添加install package报错 Package Control There are no packages available for installation

    sublime text在使用插件之前 需要安装Package Control插件 但在安装时报错 There are no packages available for installation 也就是说无法获取安装所需的包 首先确认网络
  • 基于java项目 服务器远程debug开启教程

    首先 在我们的工作中避免不了进行远程调试 我们可以通过远程debug的方式去调试我们的程序代码 通常我们的spring项目打成包的方式有jar 或者war包发布到我们的远程服务器上 我们先介绍第一种jar包方式开启远程debug 打成jar
  • JAVA 面向对象

    第五章 面向对象 面向对象技术利用对现实世界中对象的抽象和对象之间相互关联及相互作用的描述来对现实世界进行模拟 并且使其映射到目标系统中 其以基本对象模型为单位 将对象内部处理细节封装在模型内部 重视对象模块间的接口联系和对象与外部环境间的
  • 关于GRE over IPsec及IPsec over GRE

    GRE over IPsec IPsec over GRE IPSec Over GRE是先ipsec后gre 这种我没用过 GRE Over IPSec 是先gre后ipsec 也就是说ipsec是最后的承载方式 一般常用的就是这种 解决
  • 最详细的Python安装教程

    最详细的Python安装教程 一 进入Python官网首页 下载最新的Python版本 https www python org downloads 选择最新的Python3 10 5 下载64位的版本 二 下载完成后 进行安装 1 双击P
  • 数字图像处理(入门篇)六 图像数据预处理之坐标变化

    目录 1 平移 2 镜像 3 旋转 4 缩放 图像的坐标变换又称为图像的几何计算 常见的基本变换包括 平移 旋转 镜像和缩放等等 1 平移 1 代码 使用OpenCV仿射变换函数 cv2 warpAffine 实现平移操作 import n
  • 前端vue可以左右滚动的切换的tabs tabs选项卡 滑动动画效果 自动宽度

    随着技术的发展 开发的复杂度也越来越高 传统开发方式将一个系统做成了整块应用 经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改 造成牵一发而动全身 通过组件化开发 可以有效实现单独开发 单独维护 而且他们之间可以
  • Feign原理 (图解)

    1 1 简介 Feign远程调用的 Feign远程调用 核心就是通过一系列的封装和处理 将以JAVA注解的方式定义的远程调用API接口 最终转换成HTTP的请求形式 然后将HTTP的请求的响应结果 解码成JAVA Bean 放回给调用者 F
  • namespace命令空间

    目录 1 解决什么问题 2 基本介绍 2 1 定义 2 2 应用场景 3 使用案例 4 资源配额 5 标签 5 1 定义 5 2 pod资源打标签 5 3 查看标签 1 解决什么问题 命令空间类似于C 中的命名空间 当用户数量较多的集群 才
  • 使用docker搭建jupyter notebook/jupyterlab

    说明 由于官方镜像实在是不怎么好用 所以我自己做了一个优化过的jupyter notebook的镜像 notebook hub 使用我这个镜像搭建容器非常简单 下面就基于这个notebook hub来进行搭建 关于notebook hub
  • hive 报system:java.io.tmpdir错误解决

    Exception in thread main java lang IllegalArgumentException java net URISyntaxException Relative path in absolute URI sy
  • 2. IDEA + maven + protobuf配置(on mac)

    1 絮絮叨叨 都说懒惰是人类进步的源泉 有时候想想还真就那么回事 学习了如何使用protoc命令编译 重度依赖IDEA且已经习惯了maven的我 就在想是否能在IDEA中一键编译 proto文件 2 vscode配置protobuf编辑环境
  • pyecharts实现电影数据分析可视化

    根据电影数据 使用pyecharts进行可视化分析 数据介绍 import pandas as pd data pd read csv 电影 csv data head 前5行数据如下 需要安装的python库 pip install pa
  • 2.晶晨A311D-编译Ubuntu/Debian固件

    上面是我的微信和QQ群 欢迎新朋友的加入 参考 https docs khadas com zh cn vim3 FenixScript html 编译环境 我重新安装了ubuntu20 安装软件包 配置环境 sudo apt get in
  • 【数据结构】排序(直接插入、折半插入、希尔、冒泡、快速、直接选择、堆、归并、基数排序)

    一 什么是排序 排序 将一组杂乱无章的数据按一定规律顺次排列起来 即 将无序序列的数据节点包含多个数据域 那么排序往往是针对其中某个域而言 二 排序方法的分类 1 按数据存储介质可分为 内部排序 数据量不大 数据在内存 无需内外存交换数据