本文已参与「新人创作礼」活动,一起开启掘金创作之路。
主要思想:分治,但与快速排序有些不同,快速排序是先调整范围再递归左右两边,归并是先递归再归并左右两边
菜鸟教程解释
归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
- 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
- 自下而上的迭代;
算法步骤:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
- 重复步骤 3 直到某一指针达到序列尾;
- 将另一序列剩下的所有元素直接复制到合并序列尾。
步骤
- 确定分界点mid=(l+r)/2
- 递归排序left、right
- 归并,合二为一
与快排的不同:快排的分界点是元素,归并的分界点是中间位置
归并排序是稳定的,快排是不稳定的,不过没什么用,可以修改快排使之稳定,只要将每个元素都不同就可以,例如ai变为<ai,i>
时间复杂度:
nlogn
归并排序第三步是O(n),因为第一个指针只扫描前一半,第二个指针只扫描右一半,每个元素只会被比较一次
n除logn次变为1,所以功logn层
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int temp[N];
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while(i <= mid && j <= r)
{
if (q[i] < q[j]) temp[k++] = q[i++];
else temp[k++] = q[j++];
}
while(i <= mid) temp[k++] = q[i++];
while(j <= r) temp[k++] = q[j++];
for(i = l, j = 0; i <= r; i++, j++) q[i] = temp[j];
}
int main()
{
int n;
int q[N];
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d", &q[i]);
merge_sort(q, 0, n - 1);
for (int i = 0; i < n; i++) printf("%d ", q[i]);
return 0;
}