首页 > 编程语言 >排序算法 归并排序 MergeSort -- C语言实现

排序算法 归并排序 MergeSort -- C语言实现

时间:2024-08-06 23:07:11浏览次数:9  
标签:MergeSort 归并 end2 begin2 -- rangeN int 排序

归并排序

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  • 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
  • 自下而上的迭代;

用途

速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列.

也常用于外排序实现.

算法步骤

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。

递归实现

//递归归并排序分三步
/*
* 1、递归
* 2、合并
* 3、拷贝
*/

/*  时间复杂度分析
归并算法中比较耗时的是归并操作,也就是把两个子数组合并为大数组
* 每一层都要归并n个数,一共logN层,所以O(N*logN)

*/

void _MergeSort(int *a , int begin , int end ,int *tmp)
{
	//返回条件:只有一个的时候返回
	if (begin >= end)
	{	
		return;
	}

	//区间
	int mid = (begin + end) / 2;

	//类后序遍历,递归让子区间有序
	_MergeSort(a, begin, mid , tmp);//另一种时mid+1
	_MergeSort(a, mid+1, end , tmp);

	//合并
	int begin1 = begin; int begin2 = mid + 1; //左右数组最小下标(升序要从小开始比较)
	int end1 = mid;     int end2 = end;
	int i = begin; //tmp起始位置
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i] = a[begin1++];
		}
		else
		{
			tmp[i] = a[begin2++];
		}
		i++;
	}

	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

	//拷贝回去原数组
	/*
	1、一个一个交换
	2、字符函数mem系列
	*/

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

}

void MergeSort(int*a, int begin1)
{
	int *tmp = (int *)malloc( begin1 * sizeof(int));
	if (!tmp)
	{
		perror("malloc fail");
		exit(1);
	}
	_MergeSort(a, 0, begin1 - 1, tmp);
	free(tmp);
}

//当递归到只有一个数时,就相当于有序了,一个即有序,所以直接返回

非递归实现

void MergeSortNonR(int *a, int n)
{
	//range = 范围、区间。layer = 层数

	//  第一个结束下标是第二个起始下标-1    
	//  每个起始位置可以由循环次数控制 ----		设一个循环次数i  ----  要循环多少次?
	//	结束条件是:range == n
	//	下一轮区间变大可以由层数控制   ----  设一个层数控制N
	//	合并时需要两组 ,两组区间一轮循环---- 设两组起始和结束下标
	int *tmp = (int*)malloc(n*sizeof(int));
	if (!tmp)
	{
		perror("malloc fail");
		exit(-1);
	}

	int begin1 = 0;		int begin2 = 0;
	int end1 = 0;		int end2  = 0;
	//int i = 0;
	int rangeN = 1;//一个begin到end 的范围

	while (rangeN < n)
	{
		int j = 0;
		//控制变量让其进入下一轮
		
		for (int i = 0; 2 * rangeN * i < n; i++)
		{   //范围:2、4、8、16 --- 2^rangeN  == range=range*2
			//[0,1][2,3][4,5]...到[0,1,2,3][4,5,6,7][8,9,10,11]
			begin1 =  2 * rangeN * i;			// 0 ,2 ,4   /   0 ,4 ,8   /  0 , 8 ,16 , 24  /
			begin2 = begin1 + rangeN ;		// 1 ,3 ,5   /   2 ,6 ,10  /  4 ,  12, 20  , 28
			end1 = begin1 + rangeN - 1;
			end2 = begin2 + rangeN - 1;
			

			//修正
			if (end1 >= n-1)
			{
				end1 = n - 1;
				// 不存在区间
				begin2 = n;		//随便写
				end2 = n - 1;//小于begin2就行
			}
			//else if (end1 == n-1)
			//{
			//	// 不存在区间
			//	begin2 = n;
			//	end2 = n - 1;
			//}
			else if (end2 > n-1) //必须要if,否则就是end1 < n-1 => 可能出现end2 也小于n-1
			{
				end2 = n - 1;
			}

			//归并
			/*
			1、一组一组拷贝:比较一组完拷贝到tmp后,就拷贝回原数组,
			2、一轮一轮拷贝:比较完一轮所有组后,再拷贝回原数组
			*/
			j = 2 * rangeN * i;//起始位置
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j] = a[begin1++];
				}
				else
				{
					tmp[j] = a[begin2++];
				}
				j++;
			}

			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];  //只能一个一个拷,或memcpy
			}

			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			//归并完一组就拷贝回一组
			//memcpy(a + 2 * rangeN * i, tmp + 2 * rangeN * i, (end2 - 2 * rangeN * i + 1) * sizeof(int));

		}
		memcpy(a, tmp, (n)*sizeof(int));
		rangeN *= 2;
	}
}

标签:MergeSort,归并,end2,begin2,--,rangeN,int,排序
From: https://www.cnblogs.com/DSCL-ing/p/18345466

相关文章

  • [Magisk模块] 安装安卓证书的简便方法
    引言由于reqable客户端提供的安装证书模块未能使抓包正常工作,作者放弃使用reqable提供的模块并选择了另一优秀的Magisk模块MoveCertificates项目地址https://github.com/ys1231/MoveCertificate使用方法由于文档的介绍简单明了,这里只进行简要概括。下载模块刷入模......
  • 17:Python数据类型练习题
    #1获取c1,c2相同的元素列表c1=[11,22,33]c2=[22,33,44]foriinc1:ifiinc2:print(i)#2获取c1中有,c2没有的元素列表foriinc1:ifinotinc2:print(i)#3获取c2中有,c1没有的元素列表foriinc2:ifinotinc1:print(i)#4获......
  • SciTech-Mathematics-Probability+Statistics-Causation vs. Correlation: From Corre
    https://www.statology.org/from-correlation-to-causation-deep-dive-into-data-interpretation/FromCorrelationtoCausation:DeepDiveintoDataInterpretationCorrelationandCausationarekeyconceptsindataanalysis.However,correlationdoesn'tme......
  • [翻译] RFC 1928: SOCKS 协议第 5 版
    https://luyuhuang.tech/2020/08/27/rfc1928.html文档声明本文档为互联网社区规范了一个互联网标准跟踪的协议,并征求讨论和改进建议.请参阅当前版本的“互联网官方协议标准(STD1)”以获取此协议的标准化的状态.本文档的发布不受限制.致谢本文描述的协议是其之前版本(......
  • File类
    JavaFile类Java文件类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。File对象代表磁盘中实际存在的文件和目录。通过以下构造方法创建一个File对象。通过给定的父抽象路径名和子路径名字符串创建一个新的File实例。File(Fil......
  • CSS3新特性
    目录:一、选择器的扩展1.属性选择器2.伪类选择器3.伪元素选择器二、盒子模型的增强1.box-sizing属性2.边框圆角(border-radius)3.盒阴影(box-shadow)三、过渡和动画效果1.过渡效果2.动画效果四、响应式布局1.媒体查询(mediaquery)2.弹性布局(Flexbox)一、选择器......
  • 位运算符
    1.与(&)2.或(|)3.亦或(^)4.非(~)5.关于位运算的面试题问:如何用电脑将2乘8最快算出?6.左移右移的底层原理......
  • WPF Window.InputBindings KeyBinding Key
    //xaml<Windowx:Class="WpfApp233.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • 微信小程序教程011-4:京西购物商城实战之分类页实现
    文章目录4、分类4.0创建cate分支4.1渲染分类页面的基本结构4.2获取分类数据4.3动态渲染左侧的一级分类列表4.4动态渲染右侧的二级分类列表4.5动态渲染右侧的三级分类列表4.6切换一级分类后重置滚动条的位置4.7点击三级分类跳转到商品列表页面4.8分......
  • 第15天:信息打点—主机架构&蜜罐识别&WAF识别&&端口扫描&协议识别&服务安全
    时间轴主要内容1、端口扫描-应用&协议2、WAF识别-分类&识别3、蜜罐识别-分类&识别解决:1、Web服务器&应用服务器差异性2、WAF防火墙&安全防护&识别技术3、蜜罐平台&安全防护&识别技术端口服务及渗透......