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


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

❄专栏传送门:《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篇,列出来有水字数嫌疑了,就只放指针第六篇的网址,博主在指针(六)把指针部分的前五篇的网址都放在【往期回顾】了,点击【传送门】就可以看了)。

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

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

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

相关推荐
学习编程的gas1 分钟前
C++:STL中list的使用和模拟实现
开发语言·c++
shenghaide_jiahu6 分钟前
数学建模——01规划/整数规划
算法·数学建模
lsnm13 分钟前
【LINUX网络】使用TCP简易通信
linux·服务器·c语言·网络·c++·tcpdump
今晚打老虎19 分钟前
c++之基础B(第一课)
开发语言·c++
CoovallyAIHub19 分钟前
数据集分享 | PCB缺陷检测与玻璃缺陷实例分割数据集分享
深度学习·算法·计算机视觉
wa的一声哭了20 分钟前
Python多进程并行multiprocess基础
开发语言·jvm·人工智能·python·机器学习·语言模型·自然语言处理
枫叶丹434 分钟前
【Qt开发】信号与槽(三)-> 自定义信号和槽
开发语言·qt
蒟蒻小袁38 分钟前
力扣面试150题--只出现一次的数字
数据结构·算法·leetcode
RaLi和夕44 分钟前
单片机学习笔记.AD/DA(略含有SPI,用的是普中开发板上的XPT2046芯片)
c语言·笔记·单片机·嵌入式硬件·学习
奔跑吧邓邓子44 分钟前
从0到1学PHP(三):PHP 流程控制:掌控程序的走向
开发语言·php·流程控制