排序 “肆” 之归并排序

1. 归并排序

1.1 原理介绍

归并排序的基本原理是将一个未排序的数组分解较小的子数组,然后递归地对这些子数组进行排序,最后再将排好序的子数组合并成一个有序数组。其核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列

其主要步骤包括:

  1. 分割:将原始数组分割为较小的子数组,直到每个子数组只包含一个元素。
  2. 合并:逐个比较两个子数组的元素,并按顺序合并它们。

1.2 主要步骤

详细步骤:

  1. 分解:将待排序数组分解成两个大致相等的子数组,直到子数组中只有一个元素为止。这一步是通过递归实现的。
  2. 合并:将两个已排序的子数组合并成一个有序数组。在合并过程中,创建一个临时数组,比较两个子数组的元素,将较小的元素依次放入临时数组中。
  3. 递归合并:重复步骤 2,直到所有子数组都合并成一个完整的有序数组。

下面是一个示例来说明归并排序的详细步骤:

  • 假设待排序数组为 [38, 27, 43, 3, 9, 82, 10]。
  1. 初始状态:原始数组为 [38, 27, 43, 3, 9, 82, 10]。
  2. 第一次分解:将数组分解为 [38, 27, 43, 3] 和 [9, 82, 10] 两个子数组。
  3. 对左边子数组进行排序:分解左边子数组 [38, 27, 43, 3],分解为 [38, 27] 和 [43, 3];继续分解为 [38] 和 [27],以及 [43] 和 [3]。 对每个子数组进行合并排序,得到 [27, 38] 和 [3, 43]。最终合并左边子数组得到 [3, 27, 38, 43]。
  4. 对右边子数组进行排序:分解右边子数组 [9, 82, 10],分解为 [9] 和 [82, 10]。继续分解为 [82] 和 [10]。对每个子数组进行合并排序,得到 [10, 82]。最终合并右边子数组得到 [9, 10, 82]。
  5. 合并左右子数组:将左边子数组 [3, 27, 38, 43] 和右边子数组 [9, 10, 82] 合并,依次比较两个子数组的元素,将较小的元素放入临时数组中。最终得到合并后的有序数组 [3, 9, 10, 27, 38, 43, 82]。
  6. 最终结果:经过以上步骤,我们得到了完整的有序数组 [3, 9, 10, 27, 38, 43, 82]。

1.3 代码示例

cpp 复制代码
void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
		return;

	int mid = (begin + end) / 2;
	//递归排序左右两部分
	_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);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(a, 0, n - 1, tmp);

	//手动释放临时空间
	free(tmp);
}

//测试
int main()
{
	int a[] = { 2,4,6,1,5,3,9,7,0,8 };
	int n = sizeof(a) / sizeof(int);

	printf("原数组为:");
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}

	MergeSort(a, n);

	printf("\n排序后数组为:");
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	return 0;
}

1.4 特性总结

  1. 稳定性:归并排序是一种稳定的排序算法,相同元素的相对位置在排序前后不会改变。
  2. 时间复杂度:归并排序的时间复杂度为 O(N*log N),其中 N 是待排序数组的长度。
  3. 空间复杂度:归并排序的空间复杂度为 O(N),需要额外的空间来存储临时数组。
  4. 适用性:归并排序适用于各种数据规模的排序,且在处理大规模数据时表现良好。
相关推荐
先鱼鲨生40 分钟前
排序【数据结构】【算法】
数据结构·算法·排序算法
疯狂的代M夫1 小时前
数据结构 【带环链表2】
数据结构·链表
daily_23331 小时前
数据结构——小小二叉树第二幕(二叉树链式结构的实现以及二叉树的遍历)超详细!!!
数据结构·c++
小小白白蛆2 小时前
剑指offer JZ51 数组中的逆序对
数据结构·算法·排序算法
心死翼未伤2 小时前
python从入门到精通:pyspark实战分析
开发语言·数据结构·python·spark·json
码农飞飞3 小时前
详解Rust结构体struct用法
开发语言·数据结构·后端·rust·成员函数·方法·结构体
wang_changyue4 小时前
CSP-X2024解题报告(T3)
数据结构·算法·leetcode
vir024 小时前
木材加工(二分查找)
数据结构·c++·算法
程序garbage12 小时前
搜索插入位置-力扣
数据结构·算法·leetcode
vir0212 小时前
好奇怪的游戏(BFS)
数据结构·c++·算法·游戏·深度优先·图论·宽度优先