当前位置: 首页 > news >正文

归并排序(递归实现)

“归并”一词的中文含义是合并、并入的意思,而在数据结构中的定义是将两个或两个以上的有序表组合成一个新的有序表。

归并排序就是利用归并的思想实现的排序方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度是1, 然后两两合并,得到┌n/2┐(┌x┐表示不小于x的最小整数)个长度为2或1的有序子序列;再两两合并,······重复下去,直至得到一个长度为n的有序序列为止。这叫做归并排序(2路归并排序)。

#include <stdio.h>

#define MAXSIZE 10000
#define N 9
typedef struct {
	int r[MAXSIZE + 1];
	int length;
}SqList;

/*将SR[i..m]和SR[m+1..n]归并排序为TR[i..n]*/ 
void Merge(int SR[], int TR[], int i, int m, int n) {
	int j;
	int k;
	int l;
	
	for(j = m+1, k = i; i <= m && j <= n; k++) {	//将SR中的数据有小到大写入TR 
		if(SR[i] < SR[j]) {
			TR[k] = SR[i++];
		} else {
			TR[k] = SR[j++];
		}
	}
	
	if(i <= m) {	//将剩余的SR[i..m]复制到TR     
		for(l = 0; l <= m-i; l++) {
			TR[k+l] = SR[i+l];
		}
	}
	
	if(j <= n) {	//将剩余的SR[j..n]复制到TR 
		for(l = 0; l <= n-j; l++) {
			TR[k+l] = SR[j+l];
		}
	}
}

/*将SR[s..t]归并排序为TR1[s..t]*/ 
void MSort(int SR[], int TR1[], int s, int t) {
	int m;
	int TR2[MAXSIZE + 1];
	if(s == t) {
		TR1[s] = SR[s];
	} else {
		m = (s + t) / 2;	//将SR[s..t]分为 SR[s..m]和SR[m+1..t] 
		MSort(SR, TR2, s, m);	//递归将 SR[s..m]归并为TR2[s..m] 
		MSort(SR, TR2, m + 1, t);	//递归将 SR[m+1..t]归并为TR2[m+1..t]
		Merge(TR2, TR1, s, m, t);	//将 TR2[s..m] 和TR2[m+1..t]归并到 TR1[s..t]。
	}							//每次前两个函数递归返回后都会执行当前函数 
}	


/*对顺序表L进行归并排序*/
void MergeSort(SqList *L) {
	MSort(L->r, L->r, 1, L->length);
}

/*打印顺序表*/
void print(SqList L) {
	int i;
	for(i = 1; i < L.length; i++) {
		printf("%d,", L.r[i]);
	}
	printf("%d\n", L.r[i]);
}

int main() {
	int i;
	int d[N]={50,10,90,30,70,40,80,60,20};
	
	SqList L;
	for(i = 0; i < N; i++) {
		L.r[i+1] = d[i];
	}
	L.length = N;
	
	printf("排序前:\n");
    print(L);
    printf("归并排序(递归):\n");
	MergeSort(&L);
	print(L);
	
	return 0;
}

执行结果:


起初执行结果总是不正确,以为是数组下标的问题,排查后下标也没有出错。找了很久,最后发现,是Merge()函数中将SR剩余数据复制到TR代码段的 i<=m和i<=n写成了 i<=m和i<=n。一个不经意的错误,竟然让程序有了完全不一样的输出。

时间复杂度的分析:

        一趟归并需要将SR[1]~SR[n]中相邻的长度为h的有序序列进行两两合并。并且将结果放到TR1[1]~TR1[n]中,这需要将待排序的所有数据扫描一遍,因此耗费O(n)时间,并且由完全二叉树的深度可知,整个归并排序需要进行┌log₂n┐次,因此,总的时间复杂度为O(nlogn)。

空间复杂度的分析:

        归并排序在归并过程中需要与原始记录序列同样数量的存储空间存放归并排序结果(即TR[]数组空间)以及递归是深度为log₂n的栈空间,因此空间复杂度为O(n+logn)。

那么,归并排序到底稳定吗?

        归并排序是稳定的。解释如下:

        Merge()函数中if(SR[i] < SR[j])语句的两两比较不存在跳跃,因此归并排序是稳定的排序算法。

总结:归并排序是一种比较占用空间,但是效率高且稳定的算法。


相关文章:

  • 归并排序(非递归)
  • Java中final、finally和finalize的区别
  • 归并排序(自然分组)
  • STM32概述
  • 软件工程学科的诞生
  • 软件开发过程模型综述
  • 算法设计题--数组元素换位
  • 数组换位问题-比较容易理解的解法
  • C语言形参与实参的复习
  • MySQL入门学习总结
  • 计算机存储体系简介
  • Linux基本命令个人总结
  • Makefile的简单写法总结
  • 不带头节点链表--用面向对象的思想实现
  • 经典算法--约瑟夫环问题的三种解法
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 2019年如何成为全栈工程师?
  • eclipse(luna)创建web工程
  • Java编程基础24——递归练习
  • Just for fun——迅速写完快速排序
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • Python学习之路16-使用API
  • react 代码优化(一) ——事件处理
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • Vue组件定义
  • 基于 Babel 的 npm 包最小化设置
  • 简单易用的leetcode开发测试工具(npm)
  • 前端面试之CSS3新特性
  • 浅谈web中前端模板引擎的使用
  • 使用agvtool更改app version/build
  • 通过几道题目学习二叉搜索树
  • 网络应用优化——时延与带宽
  • 我有几个粽子,和一个故事
  • 自定义函数
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • PostgreSQL之连接数修改
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • (07)Hive——窗口函数详解
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (Python第六天)文件处理
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (附源码)ssm码农论坛 毕业设计 231126
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (十一)图像的罗伯特梯度锐化
  • (实战篇)如何缓存数据
  • (四)Linux Shell编程——输入输出重定向
  • (一)Java算法:二分查找
  • (转) RFS+AutoItLibrary测试web对话框