归并排序,可能并没有快速排序使用的次数多,但是归并排序作为一种重要的排序方法自然有它的独到之处。这主要跟归并算法应用的分治思想是分不开的。
分治思想一言以蔽之,就是“大事化小,小事化了”,将一个大问题分拆成若干小问题,然后将小问题逐一解决,从而也就将大问题解决了。
比如当我们面对一堆海量的数据进行排序时,数据的大小已经超出了内存的可用空间大小,这时候快速排序已经无能为力了。那么唯一的办法就是使用归并排序每次将一部分数据调进内存中,经过多次排序过程,可以实现对全部海量数据的排序。
利用将部分数据从硬盘中调进内存进行排序的方法,我们称为外部排序。归并排序也是最常用的一种外部排序。
- 时间复杂度:平均情况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);