分治算法——Merge Sort归并排序

归并排序是一种基于分治思想的稳定排序算法,尤其适用于外部排序。其时间复杂度为O(nlogn),空间复杂度为O(n)。通过递归或迭代方式实现,递归版本可能导致过多的时空消耗,而迭代版本则能有效优化这一问题。二路归并是最常见的形式,但还有多路归并,如K路归并,能减少IO开销和中间文件大小,但实现更复杂。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序,可能并没有快速排序使用的次数多,但是归并排序作为一种重要的排序方法自然有它的独到之处。这主要跟归并算法应用的分治思想是分不开的。

分治思想一言以蔽之,就是“大事化小,小事化了”,将一个大问题分拆成若干小问题,然后将小问题逐一解决,从而也就将大问题解决了。

比如当我们面对一堆海量的数据进行排序时,数据的大小已经超出了内存的可用空间大小,这时候快速排序已经无能为力了。那么唯一的办法就是使用归并排序每次将一部分数据调进内存中,经过多次排序过程,可以实现对全部海量数据的排序。
利用将部分数据从硬盘中调进内存进行排序的方法,我们称为外部排序。归并排序也是最常用的一种外部排序。

  • 时间复杂度:平均情况O(nlogn);最好情况(nlogn);最坏情况O(nlogn)
  • 空间复杂度:O(n)
  • 归并排序是一种稳定的排序方式
  • 基本思想:假设初始数组含有n个待排序变量,则可以看成是n个有序的子序列,然后两两归并,得到[n/2]([x]表示向上取整)个长度为2或1的有序子序列;再两两归并,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序
    从上面我们可以看出归并排序不仅是一种稳定的排序方式,而且时间复杂度也相对更稳定;而快排不仅是一种不稳定的排序算法,它的时间复杂度更是与排序变量的初始状态有关,最好是O(nlogn),最坏可达到O(n^2)

归并过程伪代码

在这里插入图片描述

//recursion method 递归法
#include <iostream>
using namespace std;
void mergesort(int *p,int num) {
    //mergesort function 归并函数主体
	if(num < 2) return ; //finish condition, if num less than 2, prove that it doesn't need sorting 结束条件,如果参数小于2,则证明它不需要排序
/* 	
	Variables declaration. 
	*L and *R are transition space, lCnt and rCnt are the number of variables that need to be sorted in the left and right parts.
	变量声明 *L 和 *R 是排序过程中会用到的中间空间, lCnt 和 rCNt 是左右两部分需要排序的变量数量  
*/
	int *L, *R, lCnt = (num >> 1), rCnt = num - (num >> 1);
	//num >> 1
	L = new int[lCnt]; // Apply a corresponding amount of space for the transition variable 给中间变量申请相应大小的空间
	R = new int[rCnt]; // Apply a corresponding amount of space for the transition variable 给中间变量申请相应大小的空间
	for(int i = 0; i < lCnt; ++ i) L[i] = p[i]; // Move the variables in the left part that need to be sorted to the transition space. 将左部分需要排序的变量移动到新的中间空间中
	for(int i = lCnt; i < num; ++ i) R[i - lCnt] = p[i]; // Move the variables in the right part that need to be sorted to the transition space. 将右部分需要排序的变量移动到新的中间空间中
	
	mergesort(L, lCnt); //use revursion method sorting the left subarray
	mergesort(R, rCnt); 
### 归并排序的分治法实现 归并排序是一种基于分治法的有效排序算法,通过递归地将待排序列分割成较小的部分来简化问题处理[^1]。具体来说,在分治法框架下: - **分**:数组被不断划分为两半直到每个部分仅剩下一个元素; - **治**:这些单个元素作为最小单位天然有序,随后逐步向上层回溯过程中执行合并操作——即将两个已经各自内部有序的小规模列表组合起来形成更大范围内的有序集合。 此过程可以形象化理解为树形结构中的自底向上的构建方式,其中叶子节点代表原始输入数据集里的各个独立成员,而非叶结点则表示由其孩子所对应区间经整理后的新状态。 对于Python编程语言而言,下面给出了一种典型的归并排序函数定义方法[^3]: ```python def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left_half = merge_sort(arr[:mid]) right_half = merge_sort(arr[mid:]) return merge(left_half, right_half) def merge(left, right): sorted_list = [] i = j = 0 while i < len(left) and j < len(right): if left[i] < right[j]: sorted_list.append(left[i]) i += 1 else: sorted_list.append(right[j]) j += 1 sorted_list.extend(left[i:]) sorted_list.extend(right[j:]) return sorted_list ``` 上述代码片段展示了如何利用`merge_sort()` 函数来进行递归划分工作,并借助辅助性的 `merge()` 方法完成最终融合步骤。值得注意的是,由于每次都需要额外开辟存储空间用于保存临时结果,因此该版本的空间复杂度达到了 O(n)[^2]。 ### 算法设计与分析 当讨论到性能指标方面时,归并排序展现出良好的特性: - 时间复杂度稳定保持在 \(O(N \log N)\),无论是在最坏情况还是平均情况下都如此。这是因为每一次分裂都会使得当前处理的数据量减半(`\log_2 n`) ,而在每一轮迭代里又需遍历整个长度去比较相邻项之间的大小关系 (n) 。两者相乘便得到了总的时间消耗估计值[^4]。 综上所述,尽管归并排序可能不是内存效率最高的解决方案之一,但在追求绝对速度或者面对大量重复数值的情形下,它依然是值得考虑的选择对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿扬来了

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

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

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

打赏作者

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

抵扣说明:

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

余额充值