排序 “肆” 之归并排序

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. 适用性:归并排序适用于各种数据规模的排序,且在处理大规模数据时表现良好。
相关推荐
菜鸡中的奋斗鸡→挣扎鸡6 小时前
滑动窗口 + 算法复习
数据结构·算法
axxy20007 小时前
leetcode之hot100---240搜索二维矩阵II(C++)
数据结构·算法
Uu_05kkq8 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
1nullptr10 小时前
三次翻转实现数组元素的旋转
数据结构
TT哇10 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
A懿轩A10 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
1 9 J11 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
汝即来归12 小时前
选择排序和冒泡排序;MySQL架构
数据结构·算法·排序算法
aaasssdddd9615 小时前
C++的封装(十四):《设计模式》这本书
数据结构·c++·设计模式
芳菲菲其弥章15 小时前
数据结构经典算法总复习(下卷)
数据结构·算法