归并排序_逆序对

Posted by 磊落 on May 11, 2020

逆序对

思想

  • 5 4 3 2 1 逆序对是一个数字和后边每一个比它小的数字都构成一个逆序对

  • 在归并过程中分为三类

    1. 两个数字在区间左边求逆序对:直接返回merge_sort()
    2. 两个数字在区间右边求逆序对: 直接返回merge_sort()
    3. 两个数字在区间两边求逆序对: 在归并过程中,右边数组中每加入一个数,都把左边i指针所指的值到左边区间最后端点的个数加上

特点

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;
const int N = 100010;
int q[N];
int tmp[N];
int n;


LL merge_sort(int q[], int l, int r)
{

    if (l >= r) return 0;  //res 最深处递归返回值是0. res += mid - i + 1;会逐层返回

    int mid = l + r >> 1;

    LL res = 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])
        {
            tmp[k++] = q[i++];
        }
        else {
            tmp[k++] = q[j++];
            res += mid - i + 1; //求当前合并区间的逆序对并加到总数上
        } 
    }
    
    //下边两个while最多只执行一个
    while(i <= mid)
    {
        tmp[k++] = q[i++];
    }

    while (j <= r)
    {
        tmp[k++] = q[j++];
    }

    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(q, 0, n - 1);

    return 0;
}