多种排序讲解

hello,各位小伙伴,本篇文章跟大家一起学习多种排序,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !

文章目录

  • 冒泡排序
  • 选择排序
  • 插入排序
  • 希尔排序
  • 堆排序
  • 快速排序
  • 提醒

冒泡排序

冒泡排序就是遍历数组,找到数组中最大或者最小的元素,然后放在数组开头或者结尾,然后不断遍历数组找次大的或者次小的元素,直至排序结束,光说无用,看代码演示:

void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

// 冒泡排序
void BubbleSort(int* a, int n)
{
	int end = n - 1;
	while (end > 1)
	{
		for (int i = 0; i < end; i++)
		{
			if (a[i] > a[i + 1])//找最大的
				Swap(&a[i], &a[i + 1]);
		}
		end--;
	}
}

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

选择排序

顾名思义就是选择元素来排序,但是每次遍历数组只选择一个最大或者最小元素的话效率属实太慢了,所以优化一下,每次遍历数组选择最大和最小的元素,然后将最大和最小的元素放在正确的位置,看代码:

// 选择排序
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int mini = begin, maxi = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] < a[mini])
				mini = i;
			else if (a[i] > a[maxi])
				maxi = i;
		}
		Swap(&a[begin], &a[mini]);
		if (maxi == begin) //代码1
			maxi = mini;  //代码2  
		Swap(&a[end], &a[maxi]);
		end--;
		begin++;
	}
}

由于特殊情况如:数组:6 5 4
此时min指向元素4(下标2),max指向元素6(下标0),若没有代码1和代码2,那么排序结果还是6 5 4,因为元素6和元素4交换了两次。小伙伴们可以在编译器里调试看一下。
选择排序的平均时间复杂度为 (O(n2))

插入排序

插入排序举个例子会更容易理解:3,1,2,4,5
我们要将元素3放置在元素2元素4中间,因为2 < 3 < 4,这就是插入排序的原理,找一个元素,向后比较,若比该元素小,二者交换,若比该元素大或者到达数组末尾,则停止,从另一个元素开始比较,看代码(我写的是向前比较):

// 插入排序
void InsertSort(int* a, int size)
{
	for (int i = 1; i < size; i++)
	{
		int index = i;
		int tmp = a[index];//找到要插入的元素
		while (index > 0)
		{
			if (tmp < a[index - 1])
			{
				a[index] = a[index - 1];//你比我小,你到前面的位置
				index--;
			}
			else
				break;
		}
		a[index] = tmp;//直至找到比我大的元素或者已经是数组的末尾,插入该元素
	}
}

插入排序的平均时间复杂度为 (O(n2))

希尔排序

简单来说,希尔排序就是在插入排序前进行预排序,但是:

希尔排序是一种改进的插入排序算法,它通过引入间隔(gap)来减少插入排序中元素的移动次数,从而提高排序的效率。虽然希尔排序可以看作是在插入排序前进行预排序,但具体实现上有所不同。
在希尔排序中,我们首先选择一个间隔序列(通常是 (n/2, n/4, n/8, …)),对数组进行分组,分别对每组进行插入排序。随着算法的进行,逐渐缩小间隔,直到间隔为1时,完成最后一次插入排序,此时数组已基本有序。

总的来说,希尔排序并不是简单地在插入排序前进行预排序,而是通过引入间隔和分组的方式,优化了插入排序的性能。

光说难懂,先看代码:

// 希尔排序
void ShellSort(int* a, int size)
{
	int gap = size;
	while(gap > 1)//循环直至gap==1
	{
		gap = gap / 3 + 1;//不断缩小gap的值,直至等于1
						 //(+1是为了控制gap最终会等于1)
		for (int i = 0; i < size - gap; i += gap)
		{
			int index = i;
			int tmp = a[index + gap];//分组后元素间隔为gap
			while (index >= 0)
			{
				if (tmp < a[index])
				{
					a[index + gap] = a[index];
					index -= gap;
				}
				else
					break;
			}
			a[index + gap] = tmp;
		}
	}
}

希尔排序的时间复杂度取决于间隔序列(gap sequence)的选择,通常情况下为 (O(n1.5)) 到 (O(n^2)) 之间。

堆排序

堆排序顾名思义需要建立堆来进行排序,从小到大就建立大堆,从大到小就建立小堆,为什么呢?因为我们要通过堆顶元素来进行排序,所以顺序还是逆序取决于堆顶。话不多说,看代码:

void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
void HeapSort(int* a,int size)
{
	for (int i = (size - 1 - 1) / 2; i > 0; i--)
	{
		AdjustDown(a,size,i);
	}
	int end = size - 1;
	while(end)
	{
		Swap(&a[0], &a[end]);//将堆顶的数据放置末尾
		AdjustDown(a, end,0);//然后进行向下调整,将堆变回小堆
		end--;//忽略已经被放置好的元素
	}
}

由于是将堆顶元素放在末尾,所以从小到大就建立大堆,从大到小就建立小堆

堆排序的平均时间复杂度为 (O(n \log n))

快速排序

快速排序一听名字就知道排序很快,对的,确实很快
快速排序是要每一次排序找一个基准值(一般选择第一个元素作为基准值),然后建立指针指向数组左右两端,右端指针先向左走(后面会解释),找比基准值小于等于的元素或者遇到左端指针时停下,如果没有遇到左端指针,左端指针向右走,找比基准值大于等于的元素或者遇到右端指针时停下,如果没有遇到右端指针,两指针指向的元素进行交换,重复如此,直至两指针相遇,再将基准值插入两指针相遇的位置,因为该位置左边小于等于基准值,右边大于等于基准值。
在这里插入图片描述

这样我们就得到由基准值为中心,两段分好大小的数据,然后进行递归,直至要递归的数据只有基准值而无其他元素,也就是左端指针和右端指针指向同一个位置。
话不多说,看代码:

void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;
	int begin = left, end = right;
	int keyi = begin;
	while (left < right)
	{
		while (left < right && a[right] >= a[keyi])
		{
			right--;//向左走
		}

		while (left < right && a[left] <= a[keyi])
		{
			left++;//向右走
		}
		Swap(&a[left], &a[right]);交换数据
	}
	Swap(&a[keyi], &a[left]);//插入基准值
	//进行递归,要注意传参控制排序的起始位置和结束位置
	QuickSort(a, begin, left);//左段
	QuickSort(a, left+1, end);//右段
}

快速排序的平均时间复杂度为 (O(n \log n))

提醒

时间复杂度只是分档次,并不是指最终的时间结果。

通过时间复杂度,我们可以比较不同算法在处理大规模数据时的效率。更低的时间复杂度通常意味着算法具有更好的性能,但这只是一个概略的估计,并不代表在所有情况下都适用。

好啦,这篇文章就到此结束了
所以你学会了吗?

好啦,本章对于多种排序的学习就先到这里,如果有什么问题,还请指教指教,希望本篇文章能够对你有所帮助,我们下一篇见!!!

如你喜欢,点点赞就是对我的支持,感谢感谢!!!
在这里插入图片描述

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

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

相关文章

vscode用SSH远程开发c语言

vscode配置远程 这里我使用虚拟机进行展示&#xff0c;首先需要你的虚拟机安装好ssh 没安装好就执行下面的命令安装并开启服务 sudo apt-get install ssh sudo service ssh start ps -e | grep sshvscode安装 remote-ssh扩展 点击左下角的远程连接&#xff0c;我这里已经连接…

51单片机学习笔记8 中断系统及定时器

51单片机学习笔记8 中断系统及定时器 一、中断的概念二、51单片机的中断1. 51单片机的中断源2. 中断的优先级3. 中断结构4. 外部中断解读5. 定时器中断6. 串口中断 三、中断相关寄存器1. IE 中断允许寄存器2. TCON 中断请求标志3. IP 中断优先级 四、中断号五、代码实现按键 &a…

如何使用 ArcGIS Pro 制作好看的高程渲染图

虽然 ArcGIS Pro 已经提供了很多好看的配色方案&#xff0c;但是如果直接对高程DEM进行渲染效果不是很理想&#xff0c;我们可以结合山体阴影让高程渲染图看起来更加立体&#xff0c;这里为大家介绍一下制作方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是…

【概念验证(POC):技术项目开发的关键一步】

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

g++在windows下使用C++进程库无法传入参数<求助>

如题&#xff1a; windows11使用g的时候&#xff0c;想使用下线程库。但是就发现了如题的问题。在使用时&#xff0c;不传入参数时不会报错的&#xff0c;但是传入参数之后就产生了报错。 点击进入定义发现头文件定义明明是正确的。 具体报错如下图。

3D云展平台让普通画手也能拥有自己的3D虚拟互动作品展

艺术家韩美林说过&#xff0c;我的作品都是我的孩子。 对于绘画家来说&#xff0c;每一张倾注心血和时间的画作都像自己的孩子&#xff0c;都是用心之作&#xff0c;出于某种客观或者主观原因&#xff0c;一些有才华的画家难以在线下举办画展&#xff0c;哪怕是短短几天&#x…

web表单标签加练习

表单标签 --- 行内标签 描述&#xff1a;一个完整的表单标签通常由表单域、表单控件&#xff08;表单元素&#xff09;和提示信息三部分构成 作用&#xff1a;数据交互&#xff08;C/S&#xff09; &#xff08;1&#xff09;表单域 --- <form> <form>标签用于定…

如何在尽量不损害画质的前提下降低视频占内存大小?视频格式科普及无损压缩软件推荐

大家好呀&#xff0c;相比大家都有对视频画质和体积的追求和取舍&#xff0c;那么&#xff0c;如何才能在不牺牲画质的前提下&#xff0c;尽可能的将视频大小降低到极致呢&#xff1f; 首先我们要了解视频的构成&#xff0c;要想降低视频的体积大小&#xff0c;我们可以从以下几…

Linux系统——Mysql数据库操作

目录 一、数据库基本操作 1.查看数据库结构 1.1查看数据库信息——Show databases 1.2查看数据库中的表信息——Show tables Show tables in 数据库名 use 数据库名 show tables 1.3显示数据表的结构&#xff08;字段&#xff09;——Describe&#xff08;Desc&#x…

查看angular版本的问题The Angular CLI requires a minimum Node.js version of v18.13.

angular版本与node.js版本不匹配的问题 下载安装angular 查看版本&#xff0c;发现不匹配 安装指定版本即可 查看版本并运行

网络编程-DAY6

1>创建一个武器信息库&#xff0c;包含编号&#xff08;主键&#xff09;、名称、属性、描述、价格 2>添加三把武器 3>修改某把武器的价格 4>展出价格在1000到4000的武器 5>卖掉一把武器&#xff0c;删除该武器的信息 6>几天后&#xff0c;客户顶着光头…

【Qt】使用Qt实现Web服务器(四):传递参数、表单提交和获取请求参数

1、示例 1)演示 2)提交 3)显示 2、源码 1)示例源码Demo1->FormController void FormController::service(HttpRequest& request, HttpResponse& response) {

3.6 条件判断语句cmp,je,ja,jb及adc、sbb指令

汇编语言 1. adc指令 adc是带进位加法指令&#xff0c;它利用了CF位上记录的进位值指令格式&#xff1a;adc 操作对象1&#xff0c;操作对象2功能&#xff1a;操作对象1 操作对象1 操作对象2 CF例如&#xff1a;adc ax,bx&#xff0c;实现的功能是&#xff1a;ax ax bx …

嵌入式中MCU内存管理分配算法对比

本文主要介绍内存的基本概念以及操作系统的内存管理算法。 一、内存的基本概念 内存是计算机系统中除了处理器以外最重要的资源,用于存储当前正在执行的程序和数据。 内存是相对于CPU来说的,CPU可以直接寻址的存储空间叫做内存,CPU需要通过驱动才能访问的叫做外存。…

uniapp通过script引入外部sdk的方法

文章目录 一、index.html引入二、动态引入1.App.vue引入2.单页面引入 一、index.html引入 例如 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><script>var coverSupport CSS in window && type…

【项目部署】git自动化部署项目

Git自动化部署项目 前言Git自动化部署项目自动化脚本shnodejs监听端口服务PM2启动node服务创建WebHooks 思考总结 前言 本次以egg后端项目关联gitee自动化部署为例子&#xff0c;涉及PM2进程管理工具、WebHooks、自动化脚本sh、nodejs监听端口服务等知识&#xff0c;此外服务器…

mysql笔记:23. 在Mac上安装与卸载MySQL

文章目录 下载MySQL安装包1. 打开MySQL官网&#xff0c;点击DOWNLOADS2. 点击GPL Downloads3. 点击MySQL Community Server打开下载页面4. 选择需要的文件进行下载5. ARM or x86 DMGbrewTAR卸载1. 在系统中卸载2. 在终端中卸载 MySQL对Mac电脑的适配十分强大&#xff0c;再加上…

晶圆为什么要抛光?

为什么要把晶圆打磨的这么光滑? 晶圆的最终命运是被切成一枚枚芯片(die),封装在暗无天日的小盒子里,只露出几枚引脚,芯片会看阈值,阻值,电流值,电压值,就是没人看它的颜值,我们在制程中,反复给晶圆打磨抛光,还是为了满足生产中的平坦化需要,尤其是在每次做光刻时…

使用Pygame做一个乒乓球游戏(2)使用精灵重构

本节没有添加新的功能&#xff0c;而是将前面的功能使用精灵类(pygame.sprite.Sprite) 重构。 顺便我们使用图片美化了一下程序。 看到之前的代码&#xff0c;你会发现代码有点混乱&#xff0c;很多地方使用了全局变量(global)。 本节我们将使用类进行重构。 Block(Sprite)…

【phoenix】flink程序执行phoenix,phoenix和flink-sql-connector-hbase包类不兼容

问题报错 Caused by: java.lang.RuntimeException: java.lang.RuntimeException: class org.apache.flink.hbase.shaded.org.apache.hadoop.hbase.client.ClusterStatusListener$MulticastListener not org.apache.hadoop.hbase.client.ClusterStatusListener$Listener如下图&…