DS八大排序之直接选择排序和堆排序

news2024/11/23 20:31:17

前言

上一期我们已经介绍了,排序、为什么要有排序以及排序在实际生活中的应用。并且介绍并实现了直接插入排序和它的优化即希尔排序~!本期我们再来学习一组排序 ---- "选择排序"即直接选择排序和堆排序~!

本期内容介绍

直接选择排序

堆排序

选择排序的基本思想

每次从待排序的数据元素的序列中选出最小或最大的一个元素存放在当前序列的起始位置,直到将全部待排序的数据元素排完。

直接选择排序

在元素集合a[i].....a[n-1]中,选择一个最大最小的数据,如果他不是这个序列中的最后一个第一个,则该序列中的最后一个第一个进行交换,将剩余的元素重复上述操作,直到序列的元素只有一个则结束!

OK,举个栗子画个图(这里是以升序距离的):

OK,直接选择排序的过程就是这样的,下面我们来实现一下:还是和以前一样,先写单趟再来改造整体:

单趟

int left = begin;//当前序列的最左端
int min = begin;//最小的元素的下标
for (int i = begin; i < n; i++)
{
	if (a[min] > a[i])
		min = i;
}

Swap(&a[left], &a[min]);//最左端的元素与当前序列中最小的元素交换

整体

直接选择排序改造整体也很简单,只需要,让每个元素都重复单趟即可~!

void SelectSort(int* a, int n)
{
	for (int begin = 0; begin < n; begin++)
	{
		int left = begin;//当前序列的最左端
		int min = begin;//最小的元素的下标
		for (int i = begin; i < n; i++)
		{
			if (a[min] > a[i])
				min = i;
		}

		Swap(&a[left], &a[min]);//最左端的元素与当前序列中最小的元素交换
	}
}

OK,测试一下:

OK,没有问题。这样写实每次找到当前序列中最小的一个,然后与最左端(升序)交换,我们其实可以对他进行一个小优化的--->每次找到当前序列中的两个元素(一个最小,一个最大),最小的与当前序列的最左端交换,最大与当前序列的最右端交换~!

OK,还是先写单趟,在改造多趟:

单趟

int min = begin, max = begin;
for (int i = begin + 1; i <= right; i++)
{
	if (a[min] > a[i])
		min = i;//选出最小

	if (a[max] < a[i])
		max = i;//选出最大
}

Swap(&a[begin], &a[min]);//最小与左端交换
Swap(&a[right], &a[max]);//最大与右端交换

整体

void SelectSort(int* a, int n)
{
	int begin = 0, right = n - 1;
	while (begin < right)
	{
		int min = begin, max = begin;
		for (int i = begin + 1; i <= right; i++)
		{
			if (a[min] > a[i])
				min = i;

			if (a[max] < a[i])
				max = i;
		}

		Swap(&a[begin], &a[min]);
		Swap(&a[right], &a[max]);
		++begin;
		--right;
	}
}

这就是一次选出两个的整体。OK,我们来个栗子测试一下:

怎么没有实现排序呢?是我们的思想有问题???OK,遇事不慌,调试走起:

这是调试找到的第一次最大和最小的元素的下标~!然后下来就是最小与左端交换,最大与右端交换,但此时最大恰好在最左端,一执行最小与最左端交换后在在执行在最大与最右交换时发现最大的已经不在原来的位置了~!这就导致了上述的乱序!

解决方案:在交换完最小与最左端后,判断一下最大的位置,如果最大的是在最左端,则此时最大值应该被换到了最小值的位置,因此,我们只需要调整一下最大值是在最小值的位置即可,即max = min~!

void SelectSort(int* a, int n)
{
	int left = 0, right = n - 1;
	while (left < right)
	{
		int min = left, max = left;
		for (int i = left + 1; i <= right; i++)
		{
			if (a[min] > a[i])
				min = i;

			if (a[max] < a[i])
				max = i;
		}

		Swap(&a[left], &a[min]);
		if (max == left)
			max = min;
		Swap(&a[right], &a[max]);
		++left;
		--right;
	}
}

再来测试一下:

OK,没有问题了~!

复杂度分析

时间复杂度:O(N^2)

单趟无论选择一个还是选择两个,都得遍历一遍,复杂度为O(N),整体还得遍历一遍O(N)

空间复杂度:O(1)

堆排序

堆排序其实在前面的二叉树堆那里已经介绍并实现过了,这来就等于回顾式的再过一遍~!如果想了解堆这种他是具体咋搞的请点击:二叉树的实现

堆排序(Heapsort)是指利用堆,这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据进行实现排序的。

他既然是借助堆来实现的那得有堆,即要建堆。这里有两种建堆的方式:向上调整建堆+向下调整排序,向下调整建堆+向下调整排序!

他排序是采用删除的思想把最大或最小的换到最后,然后对前N-i(i=1,2,3...n)个进行向下调整!
注意:升序建大堆,降序建小堆

OK,举个排序的例子:

向上调整建堆

void HeapSort(HPDataType* a, int n)
{
	//向上调整建堆
	//O(N*lgN)
	for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}
 
	//向下调整排序
	//O(N*lgN)
	int end = n - 1;
	while (end)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

这里的向上调整建堆和上面堆的插入是一个思路!时间复杂度是O(lgN*N),向下调整排序的时间复杂度是:O(N*lgN)---->有n个元素,每排好一个一下下标,也就是上面的删除的思路!

向下调整建堆

void HeapSort(HPDataType* a, int n)
{
	//向下调整建堆
	//O(N)
	for (int i = (n - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
 
	//向下调整排序
	//O(N*lgN)
	int end = n - 1;
	while (end)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

向下调整建堆,就是从倒数第一个元素的父节点开始向下调整为堆!这样越往上层节点的左右子树必定是堆!

OK,测试一下:

没问题~!

复杂度分析

时间复杂度:O(N*logN)

向下调整和向上调整的时间复杂度都是O(logN)即最多调整高度次,但向上调整建堆是O(N*log)而向下调整建堆的O(N)如下图~!删除排序的时间复杂度是O(N*logN),所以综合下来就是O(N*logN)

空间复杂度:O(1)

向下调整建堆时间复杂度推导

向上调整建堆时间复杂度推导

OK,本期分享就到这里,好兄弟,下期交换排序不见不散~!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 SDKMAN 管理多版本本地 Java 环境---Centos8 Windows

文章目录 windows 安装centos8 安装卸载sdkman使用 windows 安装 SDKMAN是一个 jdk 多版本管理工具&#xff0c;类似于 nodejs 中的 nvm。可以在本地存在多个 java 环境&#xff0c;快速切换功能&#xff0c;同时&#xff0c;他不止于 java sdk&#xff0c;还有maven、tomcat等…

(四)基于高尔夫优化算法GOA求解无人机三维路径规划研究(MATLAB代码)

一、无人机模型简介&#xff1a; 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 参考文献&#xff1a; [1]胡观凯,钟建华,李永正,黎万洪.基于IPSO-GA算法的无人机三维路径规划[J].现代电子技术,2023,46(07):115-120 二、高尔夫优化算法GOA简介 高尔夫优化算法…

C语言二叉树与堆的实现(一)

目录 二叉树 二叉树的分类&#xff08;目前只谈两种&#xff09; 满二叉树 完全二叉树 二叉树的性质&#xff08;其余的可以自己总结&#xff09; 选择练习 二叉树的存储结构 顺序存储方式 链式存储方式 一种完全二叉树&#xff1a;堆 堆的概念 堆的性质 建堆的时…

如何在服务器上运行python文件

目录 前置准备 详细步骤 一&#xff0c;在服务器安装Anaconda 下载安装包 上传文件到服务器 安装环境 二&#xff0c;创建虚拟环境 创建环境 三&#xff0c;测试执行python文件 执行python文件 查看进程状态 总结 前置准备 如何在个人服务器上运行python文件&#x…

熟悉SVN基本操作-(SVN相关介绍使用以及冲突解决)

一、SVN相关介绍 1、SVN是什么? 代码版本管理工具它能记住你每次的修改查看所有的修改记录恢复到任何历史版本恢复已经删除的文件 2、SVN跟Git比&#xff0c;有什么优势 使用简单&#xff0c;上手快目录级权限控制&#xff0c;企业安全必备子目录checkout&#xff0c;减少…

vivado实现分析与收敛技巧2-创建智能设计运行

智能设计运行 (IDR) 是基于标准实现运行创建的。在“ Design Runs ” &#xff08; 设计运行 &#xff09; 窗口中 &#xff0c; 右键单击实现运行 &#xff0c; 然后选择“Close Timing using Intelligent Design Runs ” &#xff08; 使用智能设计运行收敛时序 &#xff09…

深度学习手势检测与识别算法 - opencv python 计算机竞赛

文章目录 0 前言1 实现效果2 技术原理2.1 手部检测2.1.1 基于肤色空间的手势检测方法2.1.2 基于运动的手势检测方法2.1.3 基于边缘的手势检测方法2.1.4 基于模板的手势检测方法2.1.5 基于机器学习的手势检测方法 3 手部识别3.1 SSD网络3.2 数据集3.3 最终改进的网络结构 4 最后…

C++调用python: VS2017 + Anaconda + pypi第三方库

步骤一&#xff1a;在Anaconda中创建虚拟环境 这一点对大家来说应该很简单&#xff0c;简单介绍一下&#xff0c;不做过多解释。值得注意的是&#xff0c;要用conda命令创建环境&#xff0c;用pip install配置环境。 conda create -n c_python_env python3.9 # 用conda创建pyt…

Java 的第二十章:多线程

创建线程 继承Thread 类 Thread 类时 java.lang 包中的一个类&#xff0c;从类中实例化的对象代表线程&#xff0c;程序员启动一个新线程需要建立 Thread 实例。 Thread 对象需要一个任务来执行&#xff0c;任务是指线程在启动时执行的工作&#xff0c;start() 方法启动线程&am…

Docker 使用心得

创建一个docker 镜像&#xff0c;相关运行代码&#xff0c;放在docker镜像文件同级&#xff0c; pm2 不能与 docker一起使用&#xff08;&#xff09; # node 服务docker FROM node:10.16.3LABEL author"sj"RUN mkdir -p /var/nodeCOPY ./node /var/nodeWORKDIR /va…

Vue实现图片预览(Viewer.js)

摘要&#xff1a; vue项目开发中遇到一个图片预览的需求&#xff0c;可以切换下一张&#xff0c;就是花里胡哨的&#xff0c;所以找viewer.js的插件 npm install v-viewer -S在项目main.js中加入&#xff1a; Viewer.setDefaults用于更改默认配置&#xff0c;比如我不想要显示…

基于AT89C51单片机的倒数计时器设计

1&#xff0e;设计任务 利用AT89C51单片机为核心控制元件,设计一个简易的数字电压表&#xff0c;设计的系统实用性强、操作简单&#xff0c;实现了智能化、数字化。 本设计采用单片机为主控芯片&#xff0c;结合周边电路组成LED彩灯的闪烁控制系统器&#xff0c;用来控制红色…

Paraformer 语音识别原理

Paraformer(Parallel Transformer)非自回归端到端语音系统需要解决两个问题&#xff1a; 准确预测输出序列长度&#xff0c;送入预测语音信号判断包含多少文字。 如何从encoder 的输出中提取隐层表征&#xff0c;作为decoder的输入。 采用一个预测器&#xff08;Predictor&…

【Node.js】笔记整理 5 - Express框架

写在最前&#xff1a;跟着视频学习只是为了在新手期快速入门。想要学习全面、进阶的知识&#xff0c;需要格外注重实战和官方技术文档&#xff0c;文档建议作为手册使用 系列文章 【Node.js】笔记整理 1 - 基础知识【Node.js】笔记整理 2 - 常用模块【Node.js】笔记整理 3 - n…

IDEA maven无法下载源代码处理

1、使用idea内置maven 在idea中新增一个mvn运行项,截图如下: 输入命令: dependency:resolve -Dclassifiersources 2、如果外部maven&#xff0c;不使用idea内部maven 在工程目录下命令行执行命令: mvn dependency:resolve -Dclassifiersources

HX3002入耳检测光感驱动调试-感0x08 寄存器溢出,不变化错误问题解决方法

是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 读取光感0x08 寄存器溢出,不变化错误问题?原因 原因:没有读取到0x08数据,没有读0x…

2的幂运算

2的幂 描述 : 给你一个整数 n&#xff0c;请你判断该整数是否是 2 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 如果存在一个整数 x 使得 n 2x &#xff0c;则认为 n 是 2 的幂次方。 题目 : LeetCode 231.2的幂 : 231. 2 的幂 分…

vue3实现element table缓存滚动条

背景 对于后台管理系统&#xff0c;数据的展示形式大多都是通过表格&#xff0c;常常会出现的一种场景&#xff0c;从表格跳到二级页面&#xff0c;再返回上一页时&#xff0c;需要缓存当前的页码和滚动条的位置&#xff0c;以为使用keep-alive就能实现这两种诉求&#xff0c;…

centos服务器安装docker和Rabbitmq

centos服务器 一 centos安装docker1 安装docker所需要的依赖包2配置yum源3查看仓库中所有的docker版本4安装docker5 设置docker为开机自启6验证docker是否安装成功 二 使用docker安装RabbitMQ拉取RabbitMQ镜像创建并运行容器 一 centos安装docker 1 安装docker所需要的依赖包 …