【排序】归并排序(C语言实现)

文章目录

  • 1. 递归版的归并排序
  • 1.1 归并排序的思想
    • 2. 递归版的归并排序的实现
  • 2. 非递归版的归并排序




1. 递归版的归并排序


1.1 归并排序的思想

归并排序(MERGE - SORT)是建立在归并操作上的一种有效的排序算法, 该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:
在这里插入图片描述
请添加图片描述

这里我们先介绍一下递归版本的归并排序的思想:

  • 我们需要先创建一个临时数组,用来将需要排序的数组归并到这个临时数组里面去,然后再将这个数组拷贝到原数组中去,这样就完成了排序的过程。

2. 递归版的归并排序的实现

具体实现方式如下:

void Sub_MergeSort(int* a, int* tmp, int begin, int end)
{
	if (begin >= end - 1) // 我控制的是左闭右开区间
		return;

	int key = (begin + end) / 2;
	// [left,key + 1) [key,end) 左闭右开的空间一定要控制好
	int begin1 = begin, end1 = key;
	int begin2 = key, end2 = end;
	
	Sub_MergeSort(a, tmp, begin1, end1);
	Sub_MergeSort(a, tmp, begin2, end2);

	// 归并过程
	int indix = begin;
	while (begin1 < end1 && begin2 < end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[indix++] = a[begin1++];
		}
		else
		{
			tmp[indix++] = a[begin2++];
		}
	}
	while (begin1 < end1)
	{
		tmp[indix++] = a[begin1++];
	}
	while (begin2 < end2)
	{
		tmp[indix++] = a[begin2++];
	}

	// 将tmp数组中的元素拷贝到元素中
	memmove(a + begin, tmp + begin, (end - begin)*sizeof(int));
}


void MergeSort(int* a, int n)
{
	
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	// 因为这里开一次空间就够用了,所以递归过程我们还是要写成一个子函数来完成
	Sub_MergeSort(a, tmp, 0, n);

	free(tmp);
	tmp = NULL;
}


2. 非递归版的归并排序


所以在平时我们要使用归并排序时,使用递归版的完全够用了。但由于现在还在学习阶段,所以掌握一下非递归版的归并排序还是有必要的。

把递归改成非递归,这个怎么处理呢?可以像我们之前讲的快速排序的非递归一样使用栈吗?

这里实现非递归的归并排序使用栈其实不是很好的方式,反而会使问题变复杂。

在这里插入图片描述
所以我们就得想其他办法:

可以这样:
请添加图片描述
但是这里需要注意两种情况:
在这里插入图片描述
这里不控制好边界的话,很容易就造成越界了,这里我分享两种控制边界的方式,细节我写在注释里了:

方式一:

// 归并排序 -- 非递归
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail\n");
		return;
	}

	int gap = 1;
	while (gap < n)
	{
		for (int i = 0;i < n;i = 2 * gap + i)
		{
			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;
			}

			// 归并过程
			int indix = i;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[indix++] = a[begin1++];
				}
				else
				{
					tmp[indix++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[indix++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[indix++] = a[begin2++];
			}

			// 将tmp数组拷贝回原数组
			memcpy(a + i, tmp + i, (end2 - i + 1) * sizeof(int));
		}
		gap *= 2;
	}

	free(tmp);
	tmp = NULL;
}


方式二:

void MergeSortNonR2(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail\n");
		return;
	}

	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;

			// end1 >= n - 1 和begin2 >= n 都代表没有第二组,所以第二组就不用参与归并过程
			if (end1 >= n)
			{
				end1 = n - 1;

				// 此时begin2和end2一定是越界的
				// 我们手动让这段空间不存在
				begin2 = n;
				end2 = n - 1;
			}
			else if (begin2 >= n)
			{
				// 我们手动让这段空间不存在
				begin2 = n;
				end2 = n - 1;
			}
			else if (end2 >= n) // 此时end1 和 begin2都没有越界
			{
				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, tmp, sizeof(int) * n);
		gap *= 2;
	}

	free(tmp);
	tmp = NULL;
}

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

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

相关文章

快速了解VR全景拍摄技术运用在旅游景区的优势

豆腐脑加了糖、烤红薯加了勺&#xff0c;就连索菲亚大教堂前都有了“人造月亮”&#xff0c;在这个冬季&#xff0c;“尔滨”把各地游客宠上了天。面对更多的游客无法实地游玩&#xff0c;哈尔滨冰雪世界再添新玩法&#xff0c;借助VR全景拍摄技术对冬季经典冰雪体验项目进行全…

vue上传文件加进度条,fake-progress一起使用

el-upload上传过程中加进度条&#xff0c;进度条el-progress配合fake-progress一起使用&#xff0c;效果如下&#xff1a; 安装 npm install fake-progress 在用到的文件里面引用 import Fakeprogress from "fake-progress"; 这个进度条主要是假的进度条&#xff…

129基于matlab的粒子群算法、遗传算法、鲸鱼算法、改进鲸鱼算法优化最小二乘支持向量机(lssvm)的gam正则化参数和sig2RBF函数的参数

基于matlab的粒子群算法、遗传算法、鲸鱼算法、改进鲸鱼算法优化最小二乘支持向量机&#xff08;lssvm&#xff09;的gam正则化参数和sig2RBF函数的参数。输出适应度曲线&#xff0c;测试机和训练集准确率。程序已调通&#xff0c;可直接运行。 129 matlabLSSVM优化算法 (xiaoh…

14.kubernetes部署Dashboard

Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kubernetes 资源 (如 Deployment,Job,D…

云服务器租用价格表,阿里云腾讯云华为云2024年优惠对比

作为多年站长使市面上大多数的云厂商的云服务器都使用过&#xff0c;很多特价云服务器都是新用户专享的&#xff0c;本文有老用户特价云服务器&#xff0c;阿腾云atengyun.com有多个网站、小程序等&#xff0c;国内头部云厂商阿里云、腾讯云、华为云、UCloud、京东云都有用过&a…

基础篇_开发命令行程序(输入输出,类型、变量、运算符,条件语句,循环语句,方法,package与jar)

文章目录 一. 输入输出1. System.out2. System.in3. Scanner4. 变量名5. 关键字 二. 类型、变量、运算符1. 字符与字符串字符值与字符串值转义字符文本块 2. 类型何为类型数字类型字符类型 3. 变量与运算符变量运算符 4. 练习 - 房贷计算器Math.pow()数字格式化查阅 Javadoc 三…

虽然是个去年的旧新闻,但这透露了IBM的新去向

引言&#xff1a;老树盘根发新芽&#xff0c;只为云数添新彩。 【科技明说 &#xff5c; 科技热点关注】 就在2023年12月25日左右&#xff0c;外媒有消息被传入国内&#xff0c;IBM正在斥资21.3亿欧元收购德国企业软件公司Software AG旗下的两个iPaaS企业技术平台。 具体包括&…

YOLOv5 损失函数改进 | 引入 Shape-IoU 考虑边框形状与尺度的度量

🗝️改进YOLOv8注意力系列一:结合ACmix、Biformer、BAM注意力机制 论文讲解加入代码本文提供了改进 YOLOv8注意力系列包含不同的注意力机制以及多种加入方式,在本文中具有完整的代码和包含多种更有效加入YOLOv8中的yaml结构,读者可以获取到注意力加入的代码和使用经验,总…

关于网络安全,你了解多少?

随着互联网技术的飞速发展&#xff0c;网络安全问题日益凸显。国际标准化组织&#xff08;ISO&#xff09;对计算机网络安全做出了明确定义&#xff1a;为保护数据处理系统而采取的技术和管理的安全措施&#xff0c;旨在保护计算机硬件、软件和数据免受偶然和故意原因造成的破坏…

使用Pygame显示文字的示例代码

import pygame import syspygame.init()# 设置窗口尺寸 win_size (800, 600) screen pygame.display.set_mode(win_size) pygame.display.set_caption("文字显示示例")# 设置字体和文字内容 font pygame.font.SysFont(None, 48) # 使用系统默认字体&#xff0c;字…

全网最好的Java集合总结

1.List &#xff08;有序、可重复&#xff09; 1.1 ArrayList 底层是一个Object[]&#xff0c;在不指定容量的时候&#xff0c;会进行懒加载&#xff0c;创建一个{}对象&#xff0c;然后在add的时候创建一个容量为10的Object[],当数组容量不够的时候会扩容&#xff0c;每次扩容…

实现线程同步的几种方式

线程同步 1. 线程同步概念 线程同步是指多个线程协调它们的执行顺序&#xff0c;以确保它们正确、安全地访问共享资源。在并发编程中&#xff0c;当多个线程同时访问共享数据或资源时&#xff0c;可能会导致竞争条件&#xff08;Race Condition&#xff09;和其他并发问题 所…

【Python基础】一文搞懂:Python 中 csv 文件的写入与读取

文章目录 1 引言2 CSV 文件简介3 Python 中的 csv 模块4 写入 CSV 文件4.1 基本用法4.2 高级用法 5 读取 CSV 文件5.1 基本用法5.2 高级用法 6 实例演示7 注意事项8 总结 1 引言 在数据处理和数据分析领域&#xff0c;CSV (逗号分隔值) 文件是一种常见的文件格式&#xff0c;用…

Day31 贪心算法 part01 理论基础 455.分发饼干 376.摆动序列 53.最大子序和

贪心算法 part01 理论基础 455.分发饼干 376.摆动序列 53.最大子序和 理论基础&#xff08;转载自代码随想录&#xff09; 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 这么说有点抽象&#xff0c;来举一个例子&#xff1a; 例如&#…

Qt QProgressBar进度条控件

文章目录 1 属性和方法1.1 值1.2 方向1.3 外观1.4 信号和槽 2 实例2.1 布局2.2 代码实现 QProgressBar是进度条控件&#xff0c;进度条用来指示任务的完成情况 1 属性和方法 QProgressBar有很多属性&#xff0c;完整的可查看帮助文档。这里以QProgressBar为例&#xff0c;列出…

小马识途:十个营销故事 启发营销思路

在营销过程中&#xff0c;优势是相对的&#xff0c;只有凭借着客观的营销环境创造优势才能够取胜市场。在企业营销中&#xff0c;狗猛酒酸的案例比比皆是。接下来&#xff0c;就与小马识途一起来看看十个经典的营销故事吧&#xff01; 一、摩托车公司 有家德国摩托车公司&…

【Python学习】Python学习13-日期和时间

目录 【Python学习】Python学习13-日期和时间 前言通过time 获取时间戳时间元组获取当前时间&#xff0c;格式化时间格式化时间转换python中时间日期格式化符号获取日历Time 模块日历&#xff08;Calendar&#xff09;模块其他模块参考 文章所属专区 Python学习 前言 本章节主…

Sublime Text:提升编码效率的强大代码编辑器

Sublime Text是一款被广大开发者称赞的强大代码编辑器。它以其简洁、高效的设计和功能&#xff0c;成为了众多程序员的首选工具。 Sublime Text的界面简洁大方&#xff0c;没有繁琐的菜单和工具栏&#xff0c;让用户能够专注于代码编写。无论是在Windows、macOS还是Linux操作系…

1 月 21 日,三件事儿,线上不见不散丨社区活动

1 月 21 日&#xff0c;三件事儿&#xff0c;线上不见不散&#xff1a; RTE 开发者社区&#xff0c;三位联合主理人正式亮相&#xff0c;分享对于行业、社区与开发者人才发展的思考&#xff1b;「实时互动行业人才洞察2024」正式发布&#xff0c;关于行业、人才与生态的分析与…

生骨肉冻干推荐测评|希喂、VE、百利、PR等多款热门生骨肉冻干测评

随着养猫的观念逐渐科学化&#xff0c;越来越多的铲屎官开始关注猫咪主食的健康和营养问题。 冻干因其模拟猫咪原始捕猎猎物模型配比、低温加工的特点&#xff0c;被认为是最符合猫咪饮食天性的选择。 相比传统的膨化猫粮&#xff0c;生骨肉冻干中的淀粉和碳水化合物添加较少…