归并排序算法

128 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

主要思想:分治,但与快速排序有些不同,快速排序是先调整范围再递归左右两边,归并是先递归再归并左右两边

菜鸟教程解释

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  • 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
  • 自下而上的迭代;

算法步骤:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。

步骤

在这里插入图片描述

  1. 确定分界点mid=(l+r)/2
  2. 递归排序left、right
  3. 归并,合二为一

与快排的不同:快排的分界点是元素,归并的分界点是中间位置

归并排序是稳定的,快排是不稳定的,不过没什么用,可以修改快排使之稳定,只要将每个元素都不同就可以,例如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;
}