归并排序与计数排序

news2024/10/5 21:15:27

目录

1.什么是归并排序

2.归并排序的实现

3.归并排序的非递归实现     

4.计数排序


1.什么是归并排序

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的 分治(divide-and-conquer)策略 (分治法将问题分成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之),归并排序是将已有序的子序列归并得到完全有序的序列,即先使子序列有序,再使子序列段间有序。将两个有序表合并为一个有序表,称为二路归并。

动图演示:

模型展示:

2.归并排序的实现

先将区间分割,在递归分割为一个个区间,每一个子区间递归返回之后,该递归的上一层递归的子区间就是原来的区间,递归完成后,最后返回传入的整个区间,且排序完成。

那么如何排序呢:

传入区间后,进入递归,开始分割区间,最后分割为一个数的这样的区间时,不在递归,进入后面的程序,然后开始比较,每一次将最小的一次放入tmp数组中,完成子排序,在之后在copy给a,返回上一层递归,此时该层子排序,因为下一层递归的完成使得部分序列有序
故在该层继续实现子排序,使得整体已有序,在赋值给a,在返回上一层递归。。。。。,递归完成即完成排序。

void mergesort(int* a, int begin, int end, int* tmp)
{
	if (begin == end)
		return;

	int mid = (begin + end) / 2;
	// [begin, mid] [mid+1, end]
	mergesort(a, begin, mid, tmp);
	mergesort(a, mid + 1, end, tmp);

	// 归并两个区间
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
		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++];
	}

	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

void Mergesort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);

	mergesort(a, 0, n - 1, tmp);

	free(tmp);
}
int main()
{
	int a[] = { 1,5,3,6,87,10 };
	Mergesort(a, 6);
	for (int i = 0; i < 6; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

时间复杂度:O(NlogN)

空间复杂度:O(N)

3.归并排序的非递归实现     

归并排序的非递归实现直接利用循环,将分割的区间进行排序再赋值给原数组,利用gap将区间分割出来,之后修正边界,防止越界。

归并排序非递归实现的思路是使用一个增量gap来控制每一次归并的区间的元素个数,这样同样能够达到递归分解区间的效果。

归并排序要求首先把整个数组分成最小的块,每个块是有序的,然后再逐层往上排序。非递归的归并排序主要在于子序列区间的划分,可以从子序列长度为1开始进行归并,即一个数据为一个子序列,从而得到区间长度为2的子序列,并对其进行归并,又会得到区间长度为4的有序子序列4,依次往后直至整个数组排序完成。实现非递归的归并排序的思路是先用一个参数记录子序列的下标,排序子序列后,参数跳到下一个子序列的下标,排序子序列,直到排序整体。

 

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);

	// 1  2  4 ....
	int gap = 1;
	while (gap < n)
	{
		int j = 0;
		for (int i = 0; i < n; i += 2 * gap)
		{
			// 每组的合并数据
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;

			printf("[%d,%d][%d,%d]\n", begin1, end1, begin2, end2);

			if (end1 >= n || begin2 >= n)
			{
				break;
			}

			// 修正
			if (end2 >= n)
			{
				end2 = n - 1;
			}

			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++];
			}

			// 归并一组,拷贝一组
			memcpy(a+i, tmp+i, sizeof(int)*(end2-i+1));
		}
		printf("\n");
		
		//memcpy(a, tmp, sizeof(int) * n);
		gap *= 2;
	}

	free(tmp);
}

4.计数排序

作为一种非常规的排序算法,计数排序(Counting sort)是一种稳定的线性时间排序算法。该算法于1954年由 Harold H. Seward 提出。计数排序使用一个额外的数组,其中第i个元素是待排序数组中值等于i的元素的个数。

 

//计数排序
void countsort(int* a, int n)
{

	int min = a[0], max = a[0];
	for (int i = 0; i < n; i++)
	{
		if (min > a[i])
		{
			min = a[i];
		}
		if (max < a[i])
		{
			max = a[i];
		}
	}
	int range = max - min + 1;
	int* arr = (int*)malloc(sizeof(int) * range);
	memset(arr, 0, sizeof(int) * range);
    //统计
for(int i=0;i<n;i++)
    {
     arr[a[i]-min]++;
    }
    int k=0;
    //输出
for (int i=0; i < range; i++)
	{
		while (arr[i]--)
		{
			a[k++] = i+min;
		}
	}
}

时间复杂度:O(N+range)

空间复杂度:O(N)

计数排序对于数据差距不是很大的时候,其效率甚至优于快速排序,希尔排序等,相当于时间复杂度就是o(n),但时基数排序也有他的缺点:

1.数据差距较大就不适合用计数排序,其时间和空间复杂度都会很高。

2.只能排整形数据

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

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

相关文章

服务保护 Sentinel

服务保护 Sentinel Sentinel 介绍Sentinel 的下载使用Sentinel 流控规则流控规则介绍流控规则演示 Sentinel 热点规则Sentinel 隔离和熔断降级Feign 整合 Sentinel线程隔离熔断降级 Sentinel 授权规则Sentinel 系统规则Sentinel 自定义异常Sentinel 资源定义url 默认资源抛出异…

Linux常用命令——emacs命令

在线Linux命令查询工具 emacs 功能强大的全屏文本编辑器 补充说明 emacs命令是由GNU组织的创始人Richard Stallman开发的一个功能强大的全屏文本编辑器&#xff0c;它支持多种编程语言&#xff0c;具有很多优良的特性。有众多的系统管理员和软件开发者使用emacs。 语法 e…

线性磁悬浮多输入多输出(MIMO)系统的线性系统控制器设计、实现和分析(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 ​磁悬浮列车作为一种新型地面交通工具,已经在实践中得到了成功的应用。传统的EMS型磁悬浮系统在结构上简单可靠,而且在技术上…

学习C#基础知识和应用:

C#语言基础知识&#xff1a;了解C#的开发环境、变量、语法和程序结构等基础内容。这些知识是理解和开发C#自动化控制系统的前提。刚好&#xff0c;我这里有上位机入门&#xff0c;学习线路图&#xff0c;各种项目&#xff0c;需要留个6。 Winform窗体控件的应用&#xff1a;Wi…

京东零售 / hotkey 热点key探测工具使用

1、安装etcd 在etcd下载页面下载对应操作系统的etcd&#xff0c;https://github.com/etcd-io/etcd/releases 使用3.4.x以上。 2、启动worker&#xff08;集群&#xff09; 下载并编译好代码&#xff0c;将worker打包为jar&#xff0c;启动即可。如&#xff1a; java -jar $J…

北邮国院物联网 Microprocessor 微处理器笔记

Introduction-随便聊 嵌入式系统是什么&#xff1f;专用的计算机系统。为专门功能可能对计算机架构&#xff0c;外设等做出一些取舍。 通常的限制&#xff1a;Cost&#xff08;比如大量部署传感器节点&#xff09;&#xff0c;Size and weight limits&#xff08;特定应用场景…

PHP代码审计(一)之PHP代码审计的意义

PHP代码审计的意义 什么是代码审计 什么是代码审计&#xff1f;代码审计就是获取目标的源代码&#xff0c;这个目标可以是一个网站&#xff0c;也可以是一个手机app&#xff0c;只要我们得到了目标的源代码&#xff0c;我们就可以去挖掘目标系统的漏洞&#xff0c;代码审计是…

详解Jenkins配置邮件通知

前言 这几天Darren洋在使用Jenkins定时构建jmeter脚本中&#xff0c;要用到邮箱配置&#xff0c;故记录之。 一、Jenkins默认邮箱通知 这里填好smtp服务器地址和邮箱后缀&#xff0c;这样下面的账号就不用加邮箱后缀了。 网易邮箱设置以下我就不说废话文学了&#xff0c;直接上…

从零搭建ros间的通信,各功能包、节点之间的通信

新建消息类型 catkin_create_pkg car_interfaces roscpp rospy std_msgs message_generation message_runtime书写自定义的msg&#xff1a; 比如我写一个GlobalPathPlanningInterface.msg&#xff1a; float64 timestamp #时间戳 float32[] startpoint #起点位置&#x…

【技能实训】DMS数据挖掘项目-Day01

文章目录 任务1 项目准备一、开发环境二、系统简介三、项目创建 任务2【任务2.1】菜单项设计及其测试【任务2.2】使用数组存储采集的数据【任务2.3】控制显示采集的数据 任务1 项目准备 一、开发环境 1.JDK8下载及其环境变量配置(JDK8以上版本) 2.IDE &#xff1a;Eclipse 或…

马可·坎图 (Marco Cantú) 荣获尼克劳斯·沃斯奖 (Niklaus Wirth Award) Pascal最具价值贡献者奖

我们非常高兴地宣布&#xff0c;我们自己的Marco Cant荣获由西班牙萨拉曼卡大学主办的国际Pascal大会颁发的Niklaus Wirth奖。 评审团的引文最后这样一句话&#xff1a;“ Marco Cant 是Pascal社区最杰出、最原创、最杰出的人物之一”。我不认为我们自己可以说得更好。 国际Pa…

rabbitmq使用笔记

前言 mq的优点&#xff1a;异步提速、解耦、流量削峰 mq的缺点&#xff1a; mq宕机可能导致消息丢失、消费者未成功消费如果保证整个系统架构的事务安全、消息可能被重复消费出现幂等问题、消息未被消费到引发死信问题、消息出现消费延迟或消费异常引发的顺序消费错乱问题...…

Linux 修改网卡 MAC 地址

使用 iproute2 修改网卡 MAC 地址 1. 使用如下命令查看当前所有网卡及其 MAC 地址&#xff1b; sudo ip link show2. 如笔者这里想要修改网卡 ens224 的 MAC 地址&#xff0c;先使用如下命令关闭该网卡&#xff1b; sudo ip link set dev ens224 down3. 设置该网卡的 MAC 地…

阿里云:机器学习平台及OpenSearch

机器学习流程 相关项目 BladeDISC-AI编译优化 EasyRec-推荐算法库 EasyCV-视觉图像算法库 EasyNLP-NLP/多模态算法库 模型开发中算法团队面临的工程挑战 Develop platform OpenSearch 向量检索库

亚马逊云科技迁移只需5个简单步骤(2023年迁移到云)

您是否正在考虑亚马逊云科技迁移&#xff0c;并将本地项目迁移到云中&#xff1f; 但是不知道从哪里开始以及如何去做&#xff1f; 在这篇文章中&#xff0c;我将指导您完成亚马逊云科技迁移。 什么是亚马逊云科技&#xff1f; 亚马逊云科技或亚马逊网络服务是最受欢迎的云平…

jar程序部署的外部依赖和按名传参和shellUtil传参json串及返回pid问题

文章目录 指定jar程序运行的外部依赖指定参数名称传参给程序shellUtil命令传参JSON串shellUtil获取回调nohub启动程序后的pid 指定jar程序运行的外部依赖 nohup java -Djava.ext.dirs./lib/ -cp DataSourceAccessPage.jar com.sitech.adapter.JsonAdapter arg0 arg1java -cp 命…

10_SPI_Flash 连续写实验

10_SPI_Flash 连续写实验 1. 实验目标2. 连续写方法3. 操作时序4. 流程框图4.1 顶层模块4.2 连续写模块 5. 波形图6. RTL6.1 flash_seq_wr_ctrl6.2 spi_flash_seq_wr 7. Testbench 1. 实验目标 使用页写指令&#xff0c;将串口发送过来的连续不定量数据写入 Flash。本实验中&a…

Linux开发环境的搭建

文章目录 系统安装工具软件安装Xshell远程登录VScode远程登录Linux 下GCC安装 系统安装 &#xff08;虚拟机安装、云服务器&#xff09;Ubuntu18.04 网络类型&#xff1a;桥接模式网络、NAT&#xff08;network access transation)网络地址转换模式、仅主机模式 注意&#xff…

模拟电压与数字脉冲占空比控制的应用与发展前景

摘要&#xff1a;本文将讨论模拟电压控制和数字脉冲占空比控制在嵌入式控制方面的应用场景、共同点和不同点&#xff0c;并探讨它们在未来发展中的前景。 引言&#xff1a; 模拟电压控制和数字脉冲占空比控制都是嵌入式系统中常用的控制方式。模拟电压控制将电压作为控制信号&…

electron 应用优雅的配置 about 信息

使用 electron 的 dialog tray 托盘栏菜单优雅简单的配置 about 关于本应用的信息&#xff0c;效果下图所示。 项目依赖 {"electron": "^24.4.1","electron-builder": "^23.6.0","electron-builder-squirrel-windows": &q…