【排序算法】C语言实现归并排序,包括递归和迭代两个版本

本文详细介绍了归并排序算法,包括其O(nlogn)的时间复杂度和O(n)的空间复杂度,重点讲解了递归和迭代两种实现方式,以及关键的merge函数。通过分解、排序和合并步骤,展示了如何用递归和迭代策略解决问题。
摘要由CSDN通过智能技术生成

请添加图片描述

文章目录

  • 🚀前言
  • 🚀归并排序介绍及其思想
  • 🚀递归实现
  • 🚀迭代实现

🚀前言

大家好啊!阿辉接着更新排序算法,今天要讲的是归并排序,这里阿辉将讲到归并排序的递归实现迭代实现,话不多说,开始咱们今天的学习吧!!!!

🚀归并排序介绍及其思想

归并排序这是阿辉讲的第一个时间复杂度O(nlogn)的排序算法,额外空间复杂度是O(n),归并排序可以做到稳定性。

思想
归并排序的思想就是分治分治的思想是将一个大问题分解成若干个小问题,然后分别解决这些小问题,最后将这些小问题的解合并起来得到原问题的解

由分治的思想很容易,想到用递归来实现归并排序,我们接着看👇

🚀递归实现

关于归并排序的递归方法主要由三个大的逻辑组成:

  • 分解:将待排序的数组分成两个子数组
  • 解决:对每个子数组进行排序
  • 合并:将排序好的子数组合并成一个有序的数组

这里我们使用递归很轻松就能把主逻辑写好,大家都知道写递归必须要有限制条件否则会造成死递归,对于归并排序的限制条件很简单,对于数组只有一个元素时自然就是有序的,直接返回即可

主逻辑:
merge函数相当于黑盒,作用就是把两个有序数组合成一个大的有序数组

void MergeSort(int a[], int l, int r) {// C/C++归并排序递归版本,主逻辑
	if (r == l) {//递归限制条件
		return;
	}
	int m = l + ((r - l) >> 1);//数组中位置下标
	MergeSort(a, l, m);//左部分排序
	MergeSort(a, m + 1, r);//右部分排序
	merge(a, l, m, r);//两部分有序数组合并
}

整个归并排序最重要的部分也就是有序数组合并的部分:
请添加图片描述

merge函数实现,还是不太懂的可以看一下下面的代码,有详细的注释
C语言版本:

void merge(int a[], int l, int m, int r) {
	int* help = (int*)malloc((r - l + 1) * 4);//申请辅助空间
	int i = 0;//作为help指针的偏移量,存储两有序数组排好序的大数组
	int first = l;//作为左部分数组的起始下标
	int second = m + 1;//作为右部分数组的起始下标
	while (first <= m && second <= r) {//哪一方下标越界就说明不用继续比较了
		//三目运算代码更简洁,谁小谁在前先赋值给help,后置++,
		// 赋值后i向后偏移一个位置,second或first也向后偏移一个位置
		help[i++] = a[first] <= a[second] ? a[first++] : a[second++];
	}
	//下面虽然两个while循环但是只会进去一个
	//还没存进help数组的继续存
	while (first <= m) {
		help[i++] = a[first++];
	}
	while (second <= r) {
		help[i++] = a[second++];
	}
	//最后把help管理的值,还原到原数组a中
	for (i = 0; i < r - l + 1; i++) {
		a[l + i] = help[i];
	}
	free(help);//释放申请的堆空间
	help = NULL;//野指针系上绳子
}

C++版本:
也就是用了STL的容器更方便

 void merge(vector<int>& arr, int l, int mid, int r) {//合并有序数组
	vector<int> help(r - l + 1, 0);//用一个额外的数组装排好的数
	int first = l;
	int second = mid + 1;
	int i = 0;
	//合并过程
	while (first <= mid && second <= r) {
		help[i++] = arr[first] <= arr[second] ? arr[first++] : arr[second++];
	}
	while (first <= mid) {
		help[i++] = arr[first++];
	}
	while (second <= r) {
		help[i++] = arr[second++];
	}
	//将help数组拷贝到原数组
	for (int i = 0; i < r - l + 1; i++) {
		arr[l + i] = help[i];
	}
}

🚀迭代实现

归并排序的迭代实现就是把主逻辑从递归改为迭代了,有序合并部分并没有改变还是上面实现的merge函数
其实就是从递归的条件返回那一步往后推:
这里我们引入一个概念步长,用来表示左部分和右部分的数组长度,步长从1开始,然后每次倍增,就相当于递归的回溯过程
上图:
步长为左右部分长度,左右部分进行merge操作,没有右部分的跳过
请添加图片描述
主逻辑:

void MergeSort(int a[], int l, int r) {
	int len = 1;//步长
	while (len <= r) {
		l = 0;
		while (l <= r) {
			int m = l + len - 1;//计算左部分的最后一个位置
			if (m >= r) {//此时说明没有右部分,可以跳出循环进行下一轮了
				break;
			}
			//m + len是右部分的最后一个位置与r做比较防止越界,拿到一个正确的merge右边界
			int n = r <= m + len ? r : m + len;
			merge(a, l, m, n);
			l = n + 1;
		}
		if (len > r / 2) {//假如数组很长len×2可能溢出,防止溢出变成负数死循环
			break;
		}
	}
}

merge函数和前面的一样,阿辉就不水了


请添加图片描述

  • 91
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 90
    评论
以下是C语言实现归并排序算法的代码和注释: ```c #include <stdio.h> /* 归并排序函数 */ void merge_sort(int arr[], int left, int right); /* 合并两个有序数组 */ void merge(int arr[], int left, int mid, int right); /* 主函数 */ int main() { int arr[] = {3, 5, 1, 2, 6, 4}; int len = sizeof(arr) / sizeof(arr[0]); // 数组长度 merge_sort(arr, 0, len - 1); // 调用归并排序 for (int i = 0; i < len; i++) { printf("%d ", arr[i]); // 输出排序后的数组 } return 0; } void merge_sort(int arr[], int left, int right) { if (left >= right) { return; // 当数组只有一个元素时,直接返回 } int mid = (left + right) / 2; // 求中间位置 merge_sort(arr, left, mid); // 对左半部分进行递归排序 merge_sort(arr, mid + 1, right); // 对右半部分进行递归排序 merge(arr, left, mid, right); // 合并左右两个有序数组 } void merge(int arr[], int left, int mid, int right) { int len = right - left + 1; int *tmp = (int*)malloc(len * sizeof(int)); // 申请临时数组 int i = left; // 左半部分数组起始位置 int j = mid + 1; // 右半部分数组起始位置 int k = 0; // 临时数组起始位置 while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { tmp[k++] = arr[i++]; // 将左半部分数组元素放入临时数组中 } else { tmp[k++] = arr[j++]; // 将右半部分数组元素放入临时数组中 } } while (i <= mid) { tmp[k++] = arr[i++]; // 将剩余的左半部分数组元素放入临时数组中 } while (j <= right) { tmp[k++] = arr[j++]; // 将剩余的右半部分数组元素放入临时数组中 } for (int m = 0; m < len; m++) { arr[left + m] = tmp[m]; // 将临时数组中的元素复制回原数组中 } free(tmp); // 释放临时数组的内存空间 } ``` 代码注释: 1. `merge_sort`函数:归并排序函数,用于将数组的左半部分和右半部分进行递归排序,并将两个有序数组合并成一个有序数组。参数`arr`为要排序的数组,参数`left`为数组左边界,参数`right`为数组右边界。 2. `merge`函数:合并两个有序数组,用于将数组的左半部分和右半部分合并成一个有序数组。参数`arr`为原始数组,参数`left`为左半部分数组的起始位置,参数`mid`为左半部分数组的终止位置,参数`right`为右半部分数组的终止位置。 3. `main`函数:主函数,用于测试归并排序的效果。 4. 在`merge`函数中,首先计算出临时数组的长度,然后申请临时数组的内存空间。接着,使用双指针法将左半部分数组和右半部分数组进行合并,将合并后的有序数组存放在临时数组中。最后,将临时数组中的元素复制回原数组中,并释放临时数组的内存空间。 5. 在`merge_sort`函数中,首先判断数组是否只有一个元素,如果是,则直接返回。否则,计算出数组的中间位置`mid`,然后对数组的左半部分和右半部分进行递归排序,并将排序后的两个有序数组合并成一个有序数组。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 90
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿辉不一般

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值