排序(3)【归并排序】【计数排序】【排序算法度及其稳定性分析】

一.归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有 序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。利用动图更清晰的看一下过程:

在八个数中进行排序就是这样的: 

 1.归并排序的实现

void MergeSort(int* a, int* tmp, int begin, int end)
{
	if (begin >= end)
		return;
	int mid = (begin + end) / 2;//求中间值,目的是为了不断的缩小区间
	MergeSort(a, tmp, begin, mid);//从左边开始,运用递归,一层一层的缩小区间
	MergeSort(a, tmp, mid + 1, end);//这里是右区间
	int begin1 = begin, end1 = mid;//[begin,mid]与[mid+1,end]
	int begin2 = mid + 1, end2 = end;
	int i = begin;//从begin开始
	while (begin1 <= end1 && begin2 <= end2)//左右区间的值依次开始比较,比较小的那个放到新的区间,下标为i
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	//左右区间通过比较已经进入完成,接下来就是把剩下的值也输入进去
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	//这里因为我们单独创建了一个数组,所以我们需要把tmp里面的值拷贝到原来的数组里
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
	//因为我们的区间不一定从哪里开始(begin不确定),我们需要知道我们要从哪里开始拷贝,所以这里加了一个begin
}

这个代码的思想就是,我们把一个区间通过一半一半的分,分成更小的区间,然后对这小区间进行排序,再把小区间和小区间合成一个大区间,其中的每一个小区间都是有序的。这就像是一个二叉树后序的过程。

2.用非递归实现归并排序

上面对我们都是使用递归来实现排序,当然肯定有人不喜欢递归来实现。这里还有一种非递归的方式:

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);//动态创建一个数组
	if (tmp == NULL)
	{
		perror("tmp::malloc");
		return;
	}
	int gap = 1;//gap指的是每次归并几个元素
	while (gap < n)//gap不能大于等于n
	{
		for (int i = 0; i < n; i += 2 * gap)//这里的循环是把数组里的元素全部进行归并,每组数据个数是gap,还要注意i += 2 * gap指的是跳到下一组
		{
			//然后开始分区间[begin1,end1][begin2,end2]
			//归并是两组两组进行的这一个区间里的值与下一个区间里的值进行归并
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			//这里需要判断三种特殊情况,后面单独说
			if (begin2 >= n)
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			//为了不影响变量i,再创建一个变量,往tmp数组里入数据
			int j = i;
			while (begin1 <= end1&&begin2<=end2)//这里就是上面说过的入数据,左区间和右区间进行比较
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}
			//这里就是把剩余的没有入完的数据都入进去
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while(begin2<=end2)
			{
				tmp[j++]=a[begin2++];
			}
			//因为我们创建的是临时变量tmp,所以这里用memcpy
			//每次排完两组,我们就拷贝数据,如果在for循环外部,会导致一些错误,后面说
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
			
		}
		//到这里我们就已经完全的排完序了,下面就是继续增大区间,继续循环归并
		gap = gap * 2;
	}
	//还有就是别忘了释放
	free(tmp);
	tmp = NULL;
}

这里还有一些问题要说一下就是上面没有解释的那个代码:

if (begin2 >= n)
{
	break;
}
if (end2 >= n)
{
	end2 = n - 1;
}

如果我不加上面的两个if语句的话,我们会发现只有当我们的数据个数是2的n次方的时候才可以完成排序的功能。如果我有十个数的话,它就会有越界的风险。因为我每一次跳过的距离是gap,而gap是呈2的倍数增长。那么后面我在求区间的时候就会出现越界的问题。

有三种情况:

分别代表着end2越界,begin2和end2越界,end1,begin2和end2越界。 后面两种对应着第一个if语句:

if (begin2 >= n)
{
	break;
}

意思就是,如果我的begin2越界了,我就跳出这个循环,不再进行归并,因为后面的元素个数已经没有了,不需要进行归并,仅需完成前面归并的过程就行了。

然后就是第一种情况,我们只需要调整一下end2的值就行了。原本end2是越界的,我们直接让它成为最后一个元素就行了(end1之前也就是end2,在上一个过程中已经调整过了)。

如果将memcpy放在for循环外部,那么在第一次循环后就会把整个排序结果拷贝到原始数组中,导致后续的归并排序无法正确进行。比如我有11个数,那么在刚开始的时候,我有一个数就不能被拷贝进去,tmp里是10个值,此时我把tmp数组拷贝到原数组里就会出现出错。

3.归并排序的时间复杂度

归并排序的时间复杂度是O(nlogn),其中n是要排序的元素个数。归并排序的核心操作是将待排序的数组不断地分割成两个子数组,直到每个子数组只有一个元素。然后,将两个子数组合并成一个有序数组。这个分割和合并的过程需要重复logn次,每次操作的时间复杂度是O(n)。因此,归并排序的总时间复杂度是O(nlogn)。

空间复杂度是O(n)。

二.计数排序

1.计数排序的实现

这个排序是比较特殊一点的排序,它是不用比较大小就可以把数据排好的一种方式,它所用的方式是统计。

void CountSort(int* a, int n)
{
	//先找到数组里的最大值和最小值,求出数组里数据的范围
	int min = a[0];
	int max = a[0];
	for (int i = 1; i < n; i++)
	{
		if (a[i] < min)
			min = a[i];
		if (a[i] > max)
			max = a[i];
	}
	int range = max - min + 1;
	//根据范围的大小开辟空间,注意这里用的calloc直接也可以把开辟的空间里的值初始化为0
	int* count = (int*)calloc(range, sizeof(int));
	if (count == NULL)
	{
		perror("calloc fail");
		return;
	}
	//因为我们count数组里的值都是0,根据相对值,如果出现与count数组下标相同的值我们就加一
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}
	//到这里就是排序的过程,根据count数组的下标,我们把它的下标值加上min就是我们需要排序的数,依次放进数组里
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			a[j++] = i + min;
		}
	}
	free(count);
}

可能稍微用了一点比较大小的方式,但是主体我们利用了下标统计的方式来实现排序。

这个排序逻辑没有那么复杂,效率也很快,但是唯一不足的是它只能排列整数,遇到小数,负数,结构体等等都不行了。

 2.计数排序的时间复杂度

计数排序的时间复杂度为O(n+k),其中n为待排序元素的个数,k为待排序元素的取值范围。在最坏情况下,计数排序的时间复杂度可以达到O(n^2),但是当k不大时,计数排序的时间复杂度一般是线性的,即O(n)。相比于其他排序算法,计数排序的时间复杂度较低,但是需要额外的空间来存储计数数组。

三.排序算法度及其稳定性分析

 注意这里的稳定性指的是相同的数相对位置不变。

到这里一些常见的排序算法就完全结束了。感谢大家的观看,如有错误还请多多指出。

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

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

相关文章

CCAA质量管理【学习笔记】​​ 备考知识点笔记(六)质量改进系统方法与工具

第七节 质量改进系统方法与工具 1 质 量 改 进 方 法 概 述 可以说几乎每种质量管理领域的方法与工具都可以用于质量改进&#xff0c;但是一个组织在改进的整体推进中&#xff0c;往往不是采用单一的方法&#xff0c;会涉及多种改进的工具和手段&#xff0c;并依据一定的模式…

虹科免拆诊断案例 | 2022款问界M5增程式混合动力车充电口盖指示灯不工作

故障现象 一辆2022款问界M5增程式混合动力车&#xff0c;搭载1.5T发动机和发电机作为增程器&#xff0c;累计行驶里程约为3.6万km。该车因尾部受到碰撞进厂维修&#xff0c;维修后进行慢充&#xff0c;发现充电口盖指示灯不点亮&#xff08;图1&#xff09;&#xff0c;但仪表…

开放式运动耳机哪个品牌音质好用又实惠?五款2024高口碑产品精选力荐!

​开放式运动耳机在如今社会中已经迅速成为大家购买耳机的新趋势&#xff0c;深受喜欢听歌和热爱运动的人群欢迎。当大家谈到佩戴的稳固性时&#xff0c;开放式耳机都会收到一致好评。对于热爱运动的人士而言&#xff0c;高品质的开放式运动耳机无疑是理想之选。特别是在近年来…

要颜值有颜值,有性价比有性价比,华硕天选键、鼠组合分享

作为ROG产品的忠实粉丝&#xff0c;用过不少ROG 相关的产品&#xff0c;近期华硕天选TX98和天选MINI 鼠标的发布&#xff0c;独特配色令我眼前一亮。 华硕天选TX98键盘&#xff0c;作为新品&#xff0c;从看上的第一眼就觉得这款键盘是非常值得推荐。 它完美地诠释了潮玩新次元…

联想618收官:以69亿销售额勇夺15冠王

随着6月19日零点钟声的响起&#xff0c;今年的618年中大促正式落下帷幕。在这个备受瞩目的购物狂欢节里&#xff0c;联想凭借出色的产品表现和市场策略&#xff0c;再次展现了其强大的品牌实力和市场号召力。 数据显示&#xff0c;在今年618活动期间&#xff0c;联想全网销售额…

关于微信小程序(必看)

前言 为规范开发者的用户个人信息处理行为&#xff0c;保障用户的合法权益&#xff0c;自2023年9月15日起&#xff0c;对于涉及处理用户个人信息的小程序开发者&#xff0c;微信要求&#xff0c;仅当开发者主动向平台同步用户已阅读并同意了小程序的隐私保护指引等信息处理规则…

elasticsearch的安装和配置

单节点安装与部署 我们通过docker进行安装 1.docker的安装 如果以及安装了docker就可以跳过这个步骤。 首先更新yum: yum update安装docker: yum install docker查看docker的版本&#xff1a; docker -v此时我们的docker就安装成功了。 2.创建网络 我们还需要部署kiban…

计算机专业毕设-springboot论坛系统

1 项目介绍 基于SSM的论坛网站&#xff1a;后端 SpringBoot、Mybatis&#xff0c;前端thymeleaf&#xff0c;具体功能如下&#xff1a; 基本功能&#xff1a;登录注册、修改个人信息、修改密码、修改头像查看帖子列表&#xff1a;按热度排序、按更新时间排序、查看周榜月榜查…

SSMP整合案例

黑马程序员Spring Boot2 文章目录 1、创建项目1.1 新建项目1.2 整合 MyBatis Plus 2、创建表以及对应的实体类2.1 创建表2.2 创建实体类2.2.1 引入lombok&#xff0c;简化实体类开发2.2.2 开发实体类 3、数据层开发3.1 手动导入两个坐标3.2 配置数据源与MyBatisPlus对应的配置3…

创建第一个Springboot项目(环境准备、环境存在的问题、启动时存在的问题、启动的方式)

一、环境准备 专业版创建springboot&#xff0c;直接有一个选项可以选择 社区版&#xff0c;需要下载一个spring的插件 不要直接点 install 因为这个插件是付费的&#xff0c;直接点安装只有30天使用期限 在里面找免费版本的下载 然后安装 安装完成后&#xff0c;这个插件名会变…

记一次生产事故,来来回回搞了一个月

&#x1f345;我是小宋&#xff0c;关注我&#xff0c;带你轻松过面试 读源码。提升简历亮点&#xff08;14个demo&#xff09; &#x1f30f;号&#xff1a;tutou123com。拉你进专属群。 记一次生产事故&#xff0c;来来回回搞了一个月 背景 我们的主要业务是台湾省的一个小…

免费分享:2014-2021年OSM中国POI数据(附下载方法)

OpenStreetMap&#xff08;OSM&#xff09;是一个全球性的开源协作地图项目&#xff0c;允许任何人编辑和分享地理信息&#xff0c;旨在创建自由、准确且可广泛使用的世界地图。POI是“Point of Interest”的缩写&#xff0c;意为“兴趣点”。 OSM POI矢量数据是OpenStreetMap项…

通过MATLAB实现PID控制器,积分分离控制器以及滑模控制器

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 通过MATLAB实现PID控制器,积分分离控制器以及滑模控制器。通过对比三个算法可知&#xff0c;采用滑模控制算法&#xff0c;其具有最快的收敛性能&#xff0c;较强的鲁棒性&…

安装idea后配置的全局配置

1、打开IDEA应用&#xff1a;Customize→All settings...&#xff0c;如果启动IDEA后&#xff0c;默认打开的是之前的项目&#xff0c;可以关闭当前项目&#xff1a;File→Close Project&#xff0c;就退到全局配置界面了。 2、打开全局配置界面&#xff1a;Editor→File Encod…

zustand 状态管理库的使用 结合TS

zustand 是一个用于React应用的简单、快速且零依赖的状态管理库。它使用简单的钩子&#xff08;hooks&#xff09;API来创建全局状态&#xff0c;使得在组件之间共享状态变得容易。 React学习Day10 基本用法 安装&#xff1a;首先&#xff0c;你需要安装zustand库。 npm insta…

Java阻塞队列:DelayQueue

Java阻塞队列&#xff1a;DelayQueue 在Java的并发编程中&#xff0c;阻塞队列是一种非常有用的数据结构&#xff0c;它不仅提供了线程安全的队列操作&#xff0c;还在必要时会自动阻塞获取操作&#xff0c;直到队列变得不为空。本文将重点介绍一种特殊的阻塞队列——DelayQue…

亲测:无影云电脑免费三个月已经缩短为1个月

亲测&#xff1a;无影云电脑免费三个月已经缩短为1个月&#xff0c;大家不要再找3个月的无影云电脑&#xff0c;已经没有了&#xff0c;目前最新消息是1个月。以前可以领3个月&#xff0c;现在只能领1个月&#xff0c;在阿里云免费中心 https://free.aliyun.com/ 大家自己看吧&…

中国各区域人口密度可视化图

原文链接https://mp.weixin.qq.com/s?__bizMzUyNzczMTI4Mg&mid2247674303&idx1&sn830304f80a0429406c4a5e38dc7750ec&chksmfa777682cd00ff9434e4660bb52ab2bf19913b6732083de061664401a9ac0fa46581cd9e5e86&token1445576002&langzh_CN&scene21#we…

StarkNet System Architecture 系统架构

文章目录 Starknet架构排序器,证明器和节点、验证者、Starnet Core排序器 Sequencer证明器 Prover节点验证者StarkNet Core工作原理TransactionsStarknet架构 原文链接: https://david-barreto.com/starknets-architecture-review/#more-4602 StarkNet 有五个组成部分。分别…

Stable Diffusion 秋叶整合包v4.7 :解压即用,快速入门AI绘画

Stable Diffusion秋叶整合包&#xff0c;超简单一键安装Stable Diffusion&#xff0c;无任何使用门槛&#xff0c;完全免费使用&#xff0c;支持Nvdia全系列显卡&#xff0c;来自B站up秋葉aaaki&#xff0c;近期发布了Stable Diffusion整合包v4版本&#xff0c;一键在本地部署S…