【数据结构与算法】数据结构初阶:详解排序(三)——归并排序:递归版本和非递归版本


🔥个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》《数据结构与算法》C语言刷题12天IO强训LeetCode代码强化刷题

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平



**重要提醒:**为什么我们要学那么多的数据结构?这是因为没有一种数据结构能够去应对所有场景。我们在不同的场景需要选择不同的数据结构,所以数据结构没有谁好谁坏之分,而评估数据结构的好坏要针对场景,如果在一种场景下我们需要频繁地对头部进行插入删除操作,那么这个时候我们用链表;但是如果对尾部进行插入删除操作比较频繁,那我们用顺序表比较好。

因此,不同的场景我们选择不同的数据结构。


**重要提醒:**为什么我们要学那么多的数据结构?这是因为没有一种数据结构能够去应对所有场景。我们在不同的场景需要选择不同的数据结构,所以数据结构没有谁好谁坏之分,而评估数据结构的好坏要针对场景,如果在一种场景下我们需要频繁地对头部进行插入删除操作,那么这个时候我们用链表;但是如果对尾部进行插入删除操作比较频繁,那我们用顺序表比较好。

因此,不同的场景我们选择不同的数据结构。


目录

正文

[一. 比较排序](#一. 比较排序)

四、归并排序

(一)递归版本

1、思想

2、归并排序递归过程

3、代码实现

(二)非递归版本

1、代码实现

2、改进方案

(1)问题1

(2)问题2

3、完整代码

(三)归并排序的特性

结尾


这个用来测试代码的对比排序性能的代码博主还是放在下面,大家可以对比一下各种排序算法的运行时间,从而对不同排序方法的时间复杂度有更加直观地认识:

代码演示:

cpp 复制代码
//测试排序的性能对比  
void TestOP()
{
	srand(time(0));
	const int N = 100000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);
	int* a3 = (int*)malloc(sizeof(int) * N);
	int* a4 = (int*)malloc(sizeof(int) * N);
	int* a5 = (int*)malloc(sizeof(int) * N);
	int* a6 = (int*)malloc(sizeof(int) * N);
	int* a7 = (int*)malloc(sizeof(int) * N);
	for (int i = 0; i < N; ++i)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
	}
	//begin和end的时间差就是
	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();

	int begin2 = clock();
	ShellSort(a2, N);
	int end2 = clock();

	int begin3 = clock();
	SelectSort(a3, N);
	int end3 = clock();

	int begin4 = clock();
	HeapSort(a4, N);
	int end4 = clock();

	int begin5 = clock();
	QuickSort(a5, 0, N - 1);
	int end5 = clock();

	int begin6 = clock();
	MergeSort(a6, N);
	int end6 = clock();

	int begin7 = clock();
	BubbleSort(a7, N);
	int end7 = clock();

	printf("InsertSort:%d\n", end1 - begin1);
	printf("ShellSort:%d\n", end2 - begin2);
	printf("SelectSort:%d\n", end3 - begin3);
	printf("HeapSort:%d\n", end4 - begin4);
	printf("QuickSort:%d\n", end5 - begin5);
	printf("MergeSort:%d\n", end6 - begin6);
	printf("BubbleSort:%d\n", end7 - begin7);

	free(a1);
	free(a2);
	free(a3);
	free(a4);
	free(a5);
	free(a6);
	free(a7);
}

正文

一. 比较排序

四、归并排序

(一)递归版本

1、思想
2、归并排序递归过程

如下图所示------

这里我们通过式子可以求出归并排序的时间复杂度是:O(n*logn)

3、代码实现

代码演示:

cpp 复制代码
//归并排序------------递归版本
void _MergeSort(int* arr, int left, int right, int* tmp)
{
	//分解
	if (left >= right)//==也可以
	{
		return;
	}
	int mid = (left + right) / 2;
	//根据mid将[left,right]划分左右两个序列:[left,mid] [mid+1,right]
	_MergeSort(arr, left, mid, tmp);
	_MergeSort(arr, mid + 1, right, tmp);

	//合并两个序列:[left,mid] [mid+1,right]
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int index = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] < arr[begin2])
		{
			tmp[index++] = arr[begin1++];
		}
		else {
			tmp[index++] = arr[begin2++];
		}
	}
	//要么begin1序列中数据没有放完
	//要么begin2序列中数据没有放完
	while (begin1 <= end1)
	{
		tmp[index++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[index++] = arr[begin2++];
	}
	//tmp--》arr
	for (int i = left; i <= right; i++)
	{
		arr[i] = tmp[i];
	}
}
//归并排序
void MergeSort(int* arr, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	//[0,n-1]
	_MergeSort(arr, 0, n - 1, tmp);
	free(tmp);
}

(二)非递归版本

分析:

1、代码实现

代码演示:

cpp 复制代码
//归并排序------非递归版本
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	int gap = 1;
	while (gap < n)
	{
		//根据gap划分组,两两一合并
		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;

			int index = begin1;
			//两个有序序列合并
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[index] = a[begin1++];
				}
				else
				{
					tmp[index++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[index] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[index++] = a[begin2++];
			}
			//导入到原数组中
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
            //原数组开始拷贝的位置  目标位置  拷贝大小
		}
		gap *= 2;
	}
}
2、改进方案

这里前两个位置出现了随机数,哪里出了问题?

(1)问题1

这里的问题在于begin2应该为偶数,而这里是7,begin越界了。

改进:

(2)问题2

这里的问题是:end2越界了。

改进:

3、完整代码
cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS  1

//归并排序------非递归版本
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	int gap = 1;
	while (gap < n)
	{
		//根据gap划分组,两两一合并
		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;
			if (begin2 >= n)//没有右序列
			{
				break;
			}
			if (end2 >= n)//右序列不满gap个
			{
				end2 = n - 1;
			}
			int index = begin1;
			//两个有序序列合并
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[index] = a[begin1++];
				}
				else
				{
					tmp[index++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[index] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[index++] = a[begin2++];
			}
			//导入到原数组中
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
            //原数组开始拷贝的位置  目标位置  拷贝大小
		}
		gap *= 2;
	}
}

(三)归并排序的特性

1、时间复杂度:****O(nlogn)

2、空间复杂度:****O(n)


结尾

往期回顾:

【数据结构与算法】数据结构初阶:详解排序(二)------交换排序中的快速排序

【数据结构与算法】数据结构初阶:详解排序(一)------插入排序、选择排序以及交换排序中的冒泡排序

本期内容需要回顾的C语言知识如下面的截图中所示(指针博主写了6篇,列出来有水字数嫌疑了,就只放指针第六篇的网址,博主在指针(六)把指针部分的前五篇的网址都放在【往期回顾】了,点击【传送门】就可以看了)。

大家如果对前面部分的知识点印象不深,可以去上一篇文章的结尾部分看看,博主把需要回顾的知识点相关的博客的链接都放在上一篇文章了,上一篇文章的链接博主放在下面了:

【数据结构与算法】数据结构初阶:详解顺序表和链表(三)------单链表(上)

**结语:**本篇文章到这里就结束了,对数据结构的排序知识感兴趣的友友们可以在评论区留言,博主创作时可能存在笔误,或者知识点不严谨的地方,大家多担待,如果大家在阅读的时候发现了行文有什么错误欢迎在评论区斧正,再次感谢友友们的关注和支持!

相关推荐
2401_8414956412 分钟前
【操作系统】进程同步与互斥实验报告
c++·算法·操作系统·进程·并发·同步·互斥
码智社32 分钟前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海35 分钟前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖1 小时前
JDK 26 新特性详解
java·开发语言
马优晨2 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
a1117763 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao4 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
人邮异步社区4 小时前
怎么把C语言学到精通?
c语言·开发语言
爱刷碗的苏泓舒4 小时前
PPP-AR 中的参考星选取:数学原理、评价指标与切换处理
算法·gnss·模糊度固定·ppp-ar·星间单差·参考星·卫星端偏差
心平气和量大福大4 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf