归并排序

1 归并排序算法

归并排序的核心思想:分治

  1. 确定分界点:mid = (l + r) / 2
  2. 递归排序左部分和右部分
  3. 归并,合二为一

归并的方法:外排

  1. 辅助数组help[N]i指向左部分的左边界,j指向右部分的左边界;
  2. 比较q[i]q[j]的大小,小的放入help数组里;
  3. 如果左部分的没有copy将剩下的copy到help数组内,对右部分做同样的操作
  4. 最后将help数组中存储的数组copy到原数组内
#include <iostream>
using namespace std;

const int N = 100010;

int n, q[N], tmp[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 i = l, j = mid + 1, k = 0;
    
    while (i <= mid && j <= r)
    {
        if (q[i] <= q[j]) tmp[k++] = q[i++];
        else tmp[k++] = q[j++];
    }
    
    while (i <= mid) tmp[k++] = q[i++];
    while (j <= r) tmp[k++] = q[j++];
    
    for (i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &q[i]);
    
    quick_sort(q, 0, n - 1);
    
    for (int i = 0; i < n; i++) printf("%d", q[i]);
}

2 归并排序应用

逆序对数

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。

数的范围

1≤n≤100000

解决方法

使用归并排序的思想:

假设现在的merge_sort函数可以返回数组中所有的逆序对的个数

归并排序:

1、找数组的中间点mid,将数组分为[l, mid]和[mid + 1, r];

2、递归排序左部分,递归排序右部分

3、合并左右区间

逆序对产生的情况:

1、两个数同时出现在左半边:merge_sort(L, mid)

2、两个数同时出现在右半边:merge_sort(mid + 1, R)

3、一个数在左一个数在右

对于第三种情况,整体的思路:右半边的第一个数,看左半边部分中有多少个比其大,以此类推遍历整个右半边的数

归并排序中的归并过程中,有两个指针i, j分别指向左右部分,谁小会将谁添加到辅助数组内,当q[i] > q[j]时,此时[i, mid]之间的数都大于q[j],这时就会产生mid -i + 1个逆序对也就是说,在归并的过程中,当要输出q[j]时,此时给最终的逆序对的结果就加上mid - i + 1即可。

逆序对最多的数量:整个数组为逆序是的逆序对最多,最多为n(n-1)/2个。

#include <iostream>

using namespace std;

const int N = 100010;

typedef long long LL;

int n;
int q[N], tmp[N];

LL merge_sort(int l, int r)
{
    if (l >= r) return 0;
    
    int mid = l + r >> 1;
    LL res = merge_sort(l, mid) + merge_sort(mid + 1, r);
    
    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
    {
        if (q[i] <= q[j]) tmp[k++] = q[i++];
        else 
        {
            tmp[k++] = q[j++];
            res += mid - i + 1;
        }
    }
    
    while (i <= mid) tmp[k++] = q[i++];
    while (j <= r) tmp[k++] = q[i++];
    
    for (int i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
    
    return res;
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i++) cin >> q[i];
    
    cout << merge_sort(0, n - 1);
}
posted @ 2021-05-24 14:28  Dabric  阅读(98)  评论(0编辑  收藏  举报
TOP