25.选择排序,归并排序,基数排序

目录

一. 选择排序

(1)简单选择排序

(2)堆排序

二. 归并排序

三. 基数排序

四. 各种排序方法的比较

(1)时间性能

(2)空间性能

(3)排序方法的稳定性能

(4)关于“排序方法的时间复杂度的下限”


一. 选择排序

(1)简单选择排序

基本思想:在待排序的数据中选出最大(小)的元素放在其最终的位置。
基本操作:
1.首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换。
2.再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换。
3.重复上述操作,共进行n-1趟排序后,排序结束。

 

 不难写出算法:

void SelectSort(SqList &L){
    for(i=1; i<L.length; ++i){
        k=i;  //第i趟从第i个元素开始
        for(j=i+1; j<=L.length; j++)
            if(L.r[j].key < L.r[k].key) k=j;  //记录最小值位置
        if(k!=i)  L.r[i]←—→L.r[k];  //交换
    }
}

下面我们分析时间复杂度。对移动次数来说,最好情况是0,最坏情况是3(n-1),也就是每一趟都得移动(每次移动需要移动3次)。对比较次数来说,无论待排序列处于什么状态,选择排序所需进行的"比较”次数都相同,为\sum_{i=1}^{n-1}(n-i)=\frac{n}{2}(n-1)

上面的算法是不稳定排序(但是可以稳定化)。具体的说用数组实现的选择排序是不稳定的,用链表实现的选择排序是稳定的。例如,给定8,5,8*,7,9;第1次:5,8,8*,7,9;第2次:5,7,8*,8,9;从而可以验证它是不稳定的。

(2)堆排序

堆的定义:若n个元素的序列{\left \{ a_1,a_2...a_n \right \}}满足\left\{\begin{matrix} a_i\leqslant a_{2i}\\ a_i\leqslant a_{2i+1} \end{matrix}\right.\left\{\begin{matrix} a_i\geqslant a_{2i}\\ a_i\geqslant a_{2i+1} \end{matrix}\right.,则分别称该序列为小根堆和大根堆。从堆的定义可以看出,堆实质是满足如下性质的完全二叉树:二叉树中任一非叶子结点均小于(大于)它的孩子结点。

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

那么怎么重建呢?以小(大)根堆为例:
1.输出堆顶元素之后,以堆中最后一个元素(编号最大的元素)替代之;
2.然后将根结点值与左、右子树的根结点值进行比较,并与其中小(大)者进行交换;
3.重复上述操作,直至叶子结点,将得到新的堆,称这个从堆顶至叶子的调整过程为“筛选”。

例如,对下面的小根堆,把13输出,最后一个元素97作为根结点,它的左右孩子是38和27,27较小,所以把97和27交换。此时97的左右孩子是65和49,49较小,把49和97交换,这个时候97已经是叶子结点就不用再操作了。

 写出算法如下:

void HeapAdjust(elem R[], int s, int m){
/*已知R[s..m]中记录的关键字除R[s]之外均满足堆的定义,本函数调整R[s]的关键字,使R[s..m]成为一个大根堆*/
    rc = R[s];
    for (j=2*s; j<=m; j *= 2){  //沿key较大的孩子结点向下筛选
        if (j < m && R[j] < R[j+1]) ++j;  //j为key较大的记录的下标
        if (rc >= R[j]) break;  //rc大于左右孩子,这个时候已经符合要求,就不用做了
        R[s] = R[j];  //较大的孩子结点往上升
        s = j;  //rc应插入在位置s上,更新s
    }//for
    R[s] = rc;  //插入
}//HeapAdjust

HeapAdjust函数是一个用于调整堆的函数。它接受一个数组R,以及两个整数s和m作为参数。s表示要调整的子树的根节点的位置,m表示该子树的最后一个节点的位置。

首先,将根节点的值保存在变量rc中。然后,通过一个循环来比较根节点和其子节点的值。在循环中,变量j初始化为根节点的左子节点的位置(2*s),然后每次乘以2,即可得到下一个子节点的位置。在循环中,首先判断是否存在右子节点,并且右子节点的值是否大于左子节点的值。如果满足条件,则将j加1,即将j指向右子节点。然后,判断rc的值是否大于等于R[j]的值。如果满足条件,则退出循环。如果rc的值小于R[j]的值,则将R[j]的值赋给R[s],即将较大的子节点的值上移到根节点的位置。然后,将s更新为j,即将s指向较大子节点的位置。循环结束后,将rc的值赋给R[s],即将根节点的值放到合适的位置上。这样,HeapAdjust函数完成了对以s为根节点的子树的调整,使其满足堆的性质。

可以看出:对一个无序序列反复“筛选”就可以得到一个堆。即:从一个无序序列建堆的过程就是一个反复“筛选”的过程。我们重新考察堆的定义,显然:单结点的二叉树是堆,在完全二叉树中所有以叶子结点(序号i > n/2,这里是整除向下取整)为根的子树也是堆。这样,我们只需依次将以序号为n/2,n/2 - 1,.....1的结点为根的子树均调整为堆即可。即:对应由n个元素组成的无序序列,“筛选”只需从第n/2个元素开始。

由于堆实质上是一个线形表,那么我们可以顺序存储一个堆。下面以一个实例介绍建一个小根堆的过程。例如给定关键字为49,38,65,97,76,13,27,49的一组记录,将其按关键字调整为一个小根堆:

将初始无序的R[1]到R[n]建成一个小根堆,可用以下语句实现:

for(i = n/2 ; i >= 1; i--)
    HeapAdjust (R, i, n);

上面我们了解了怎么建堆。若对一个无序存列建堆,然后输出根。重复该过程就可以由一个无需序列输出有序序列。实质上,堆排序就是利用完全二叉树中父结点与孩子结点之间的内在关系来排序的。

void HeapSort(elem R[]){  //对R[1]到R[n]进行堆排序
    int i;
    for (i = n/2; i>= 1; i--)
    HeapAdjust(R, i, n);//建初始堆
    for (i = n; i > 1; i--){  //进行n-1趟排序
        Swap(R[1], R[i]);  //根与最后一个元素交换,也就是把根结点输出并放在最后一个位置
        HeapAdjust(R, 1, i-1);  //对R[1]到R[i-1]重新建堆}
}//HeapSort

最后我们来研究时间复杂度。初始堆化所需时间不超过O(n),排序阶段(不含初始堆化)每次重新堆化所需时间不超过O(logn),则n-1次循环所需时间不超过O(nlogn)。因此:
Tw(n)=O(n)+ O(nlogn)= O(nlogn)

堆排序的时间主要耗费在建初始堆和调整建新堆时进行的反复筛选上。堆排序在最坏情况下,其时间复杂度也为O(nlog2n),这是堆排序的最大优点。无论待排序列中的记录是正序还是逆序排列,都不会使堆排序处于"最好"或"最坏"的状态。另外,堆排序仅需一个记录大小供交换用的辅助存储空间。

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

二. 归并排序

基本思想:将两个或两个以上的有序子序列“归并”为一个有序予列。在内部排序中,通常采用的是2-路归并排序。即:将两个位置相邻的有序子序列R[1..m]和R[m+1..n]归并为一个有序序列R[1..n]。

这种树称为归并树。n个元素归并排序只需要\left \lceil log_2n \right \rceil趟。下面讨论怎么把两个有序序列合并成一个有序序列。这里可以参考线性表的合并算法。设R[low]-R[mid]和R[mid+1]-R[high]为相邻,归并成一个有序序列R1[low] - R1[high].

若SR[i].key<=SR[j].key,则TR[k]=RS[i];k++;i++;  否则,TR[k]=SR[j];k++;j++;

归并排序的时间效率是O(nlog2n),空间效率是O(n),因为需要一个与原始序列同样大小的辅助序列(TR)。这正是此算法的缺点。归并排序算法是稳定的算法。

三. 基数排序

基本思想:分配+收集

基数排序也叫桶排序或箱排序:设置若干个箱子,将关键字为k的记录放入第k个箱子,然后在按序号将非空的连接。基数排序的数字是有范围的,均由0-9这十个数字组成,则只需设置十个箱子,相继按个、十、百...进行排序。例:给定待排序序列(614,738,921,485,637,101,215,530,790,306)。这里每一个箱子都是一个队列,遵循先进先出的原则:

至此排序完成!基数排序的时间效率:O(k*(n+m)),其中k:关键字个数(上面有3个关键字),m:关键字取值范围为m个值(上面为10),n:元素个数。这里,每一趟分配n个元素,收集m个桶,总共需要k遍。

空间效率:这里需要放置m个桶,回收的时候回收n个元素,则空间复杂度是O(n+m)。基数排序是稳定的。

四. 各种排序方法的比较

(1)时间性能

1.按平均的时间性能来分,有三类排序方法:

  • 时间复杂度为O(nlogn)的方法有:快速排序、堆排序和归并排序,其中以快速排序为最好;
  • 时间复杂度为O(n^2)的有:直接插入排序、冒泡排序和简单选择排序,其中以直接插入为最好,特别是对那些对关键字近似有序的记录序列尤为如此;
  • 时间复杂度为O(n)的排序方法只有:基数排序。

2.当待排记录序列按关键字顺序有序时,直接插入排序和冒泡排序能达到到O(n)的时间复杂度;而对于快速排序而言,这是最不好的情况,此时的时间性能退化为O(n^2),因此是应该尽量避免的情况。
3.简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。

(2)空间性能

指的是排序过程中所需的辅助空间大小.
1.所有的简单排序方法(包括:直接插入、冒泡和简单选择)和堆排序的空间复杂度为O(1)
2.快速排序为O(logn),为栈所需的辅助空间
3.归并排序所需辅助空间最多,其空间复杂度为O(n)
4.链式基数排序需附设队列首尾指针,则空间复杂度为O(rd)

(3)排序方法的稳定性能

稳定的排序方法指的是,对于两个关键字相等的记录,它们在序列中的相对位置,在排序之前和经过排序之后,没有改变。

  • 当对多关键字的记录序列进行LSD方法排序时,必须采用稳定的排序方法。
  • 对于不稳定的排序方法,只要能举出一个实例说明即可。
  • 快速排序和堆排序是不稳定的排序方法。

(4)关于“排序方法的时间复杂度的下限”

本章讨论的各种排序方法,除基数排序外,其它方法都是基于“比较关键字”进行排序的排序方法,可以证明,这类排序法可能达到的最快的时间复杂度为O(nlogn)。(基数排序不是基于“比较关键字”的排序方法,所以它不受这个限制)。

可以用一棵判定树来描述这类基于“比较关键字”进行排序的排序方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/100220.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

美创科技获通信网络安全服务能力评定(应急响应一级)认证!

近日&#xff0c;中国通信企业协会公布通信网络安全服务能力评定2023年第一批获证企业名单。 美创科技获得应急响应一级资质&#xff0c;成为2023年第一批获证企业之一&#xff01; 通信网络安全服务能力评定是对通信网络安全服务单位从事通信网络安全服务综合能力的评定&#…

Revit SDK 介绍:CreateAirHandler 创建户式风管机

前言 这个例子介绍如何通过 API 创建一个户式风管机族的内容&#xff0c;包含几何和接头。 内容 效果 核心逻辑 必须打开机械设备的族模板创建几何实体来表示风管机创建风机的接头 创建几何实体来表示风管机 例子中创建了多个拉伸&#xff0c;下面仅截取一段代码&#xff…

python爬虫—requests

一、安装 pip install requests 二、基本使用 1、基本使用 类型 &#xff1a; models.Response r.text : 获取网站源码 r.encoding &#xff1a;访问或定制编码方式 r.url &#xff1a;获取请求的 url r.content &#xff1a;响应的字节类型 r.status_code &#xff1a;响应…

山西省文物局与大势智慧签订战略合作协议

8月24日&#xff0c;由山西省文物局、中国文物信息咨询中心(国家文物局数据中心)主办的数字文博发展论坛在太原举行。武汉大势智慧科技有限公司&#xff08;后简称“大势智慧”&#xff09;受邀参与&#xff0c;与来自国内文博数字化领域的专家学者齐聚一堂&#xff0c;围绕“数…

什么是同源策略(same-origin policy)?它对AJAX有什么影响?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 同源策略&#xff08;Same-Origin Policy&#xff09;与 AJAX 影响⭐ 同源策略的限制⭐ AJAX 请求受同源策略影响⭐ 跨域资源共享&#xff08;CORS&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记…

K 次取反后最大化的数组和【贪心算法】

1005 . K 次取反后最大化的数组和 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 以这种方式修改数组后&#xff0c;返回数组 可能…

02_nodejs开发环境安装

02 【nodejs开发环境安装】 1.版本介绍 在命令窗口中输入 node -v 可以查看版本0.x 完全不技术 ES64.x 部分支持 ES6 特性5.x 部分支持ES6特性&#xff08;比4.x多些&#xff09;&#xff0c;属于过渡产品&#xff0c;现在来说应该没有什么理由去用这个了6.x 支持98%的 ES6 特…

zabbix安装部署

前期准备&#xff1a;安装mysql数据库和nginx 一、下载zabbix rpm -Uvh https://repo.zabbix.com/zabbix/4.4/rhel/7/x86_64/zabbix-release-4.4-1.el7.noarch.rpm yum-config-manager --enable rhel-7-server-optional-rpms yum install epel-release numactl yum install…

Metasploit“MSF”连接postgresql时因排序规则版本不匹配导致无法连接

一、问题 更新Kali之后使用Metasploit时出现一个问题&#xff0c;连接postgresql时因排序规则版本不匹配导致无法连接 警告: database "msf" has a collation version mismatch DETAIL: The database was created using collation version 2.36, but the operati…

Linux操作系统中的信号剖析,

1、前言 信号是一种信息载体&#xff0c;在现实中&#xff0c;信号就是表示消息的物理量&#xff0c;比如说红绿灯&#xff0c;古时候狼烟等等&#xff0c;就拿红绿灯来说&#xff0c;为什人和车辆都是看到绿灯才会通行&#xff0c;红灯亮了就要停下来&#xff0c;因为这是现实…

Dolphin for Mac(Wii游戏模拟器)配置指南

Wii模拟器Dolphin Mac是款适合Mac电脑中的游戏玩家们使用的模拟器工具。Wii模拟器Dolphin Mac官方版支持直接运行游戏镜像文件&#xff0c;玩家可以将游戏ISO拷贝到某一个文件夹中统一进行管理。Wii模拟器Dolphin Mac除了键盘和鼠标外&#xff0c;还支持配合原版的Wii遥控器操作…

1、[春秋云镜]CVE-2022-32991

文章目录 一、相关信息二、解题思路&#xff08;手注&#xff09;三、通关思路&#xff08;sqlmap&#xff09; 一、相关信息 靶场提示&#xff1a;该CMS的welcome.php中存在SQL注入攻击。 NVD关于漏洞的描述&#xff1a; 注入点不仅在eid处&#xff01;&#xff01;&#xff…

Screaming Frog SEO Spider,为您的网站提供全方位的优化解决方案

Screaming Frog SEO Spider是一款适用于Mac的软件&#xff0c;它可以帮助用户分析网站的优化信息。该软件可以模拟蜘蛛爬行的方式&#xff0c;抓取网站的各种信息&#xff0c;并将这些信息整理成易于理解的报告。这些报告可以帮助用户评估网站的优化情况&#xff0c;发现链接的…

前端将UTC时间格式转化为本地时间格式~~uniapp写法

UTC时间格式是什么 首先我们先简单的了解一下&#xff1a;UTC时间&#xff08;协调世界时&#xff0c;Coordinated Universal Time&#xff09;使用24小时制&#xff0c;以小时、分钟、秒和毫秒来表示时间 HH:mm:ss.SSSHH 表示小时&#xff0c;取值范围为00到23。mm 表示分钟…

pip安装第三方库与设置

pip的使用 假如下载numpy pip install numpypypi 镜像源「配置」 常用镜像源列表 官方&#xff1a;https://pypi.org/simple 百度&#xff1a;https://mirror.baidu.com/pypi/simple/ 清华&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple 阿里&#xff1a;https://m…

Mac软件删除方法?如何删除不会有残留

Mac电脑如果有太多无用的应用程序&#xff0c;很有可能会拖垮Mac系统的运行速度。因此&#xff0c;卸载电脑中无用的软件是优化Mac系统运行速度的最佳方式之一。Mac卸载应用程序的方式是和Windows有很大的区别&#xff0c;特别对于Mac新用户来说&#xff0c;如何无残留的卸载删…

【线性代数】矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇)

矩阵求导的本质与分子布局、分母布局的本质&#xff08;矩阵求导——本质篇&#xff09; 说在前面一. 函数与标量、向量、矩阵二. 矩阵求导的本质三. 矩阵求导结果的布局四. 分子布局、分母布局的本质五. 向量变元的实值标量函数 说在前面 我将严谨地说明矩阵求导的本质与分子布…

MongoDB - 安装

一、Docker安装MongoDB 1. 安装 安装版本: 7.0.0 docker run -itd --name mongodb -v C:\\data\\mongodb\\data:/data/db -p 27017:27017 mongo:7.0.0 --auth-v: 将容器目录/data/db映射到本地C:\\data\\mongodb\\data目录&#xff0c;防止容器删除数据丢失-p: 端口映射--aut…

Linux系统下建立Socket聊天服务器

目录 1.服务器结构 2.各模块函数 2.1 socket函数 2.2 bind函数 2.3 Listen函数 2.4 accept函数 2.5 接收发送函数 2.6 close函数 2.7 connect函数 3 代码段 3.1 服务器代码 1.服务器结构 使用socket的API函数编写服务端和客户端程序的步骤图示: 2.各模块函数 服务…

TensorFlow 的基本概念和使用场景介绍

文章目录 一、TensorFlow基本概念1. 张量&#xff08;Tensor&#xff09;2. 计算图&#xff08;Computation Graph&#xff09;3. 会话&#xff08;Session&#xff09; 二、TensorFlow使用场景1. 机器学习&#xff08;Machine Learning&#xff09;2. 计算机视觉&#xff08;C…