归并排序思想及其应用(判断逆序对)

归并排序分为两步:

1.将序列递归处理,每次都将序列分成两份。

2.将左右两边有序合并后回溯到上一层(当只有一个数时默认有序,所以只有一个数时是递归的出口)

排序过程图示:

归并排序思想及其应用(判断逆序对)_第1张图片

将序列左右两边有序排列的方法:双指针

两个指针分别指向左右两个序列,对比两个指针位置上数的大小,将小的放到辅助空间中,并且将该指针向前移动,移动完后将辅助空间内的序列覆盖到原有序列位置上。

归并排序代码模板如下:

#include
using namespace std;
const int N = 1e5 + 10;
int q[N];
int tmp[N];//合并左右两段时需要借助一个辅助空间

void merge_sort(int l, int r) {
    if (l >= r)return;//递归出口,如果只有一个数

    int mid = (l + r) >> 1;
    merge_sort(l, mid), merge_sort(mid + 1, r);//递归

    int i = l, j = mid + 1;//双指针
    int u = 0;//辅助空间的指针

    while (i <= mid && j <= r) {//有序合并两段序列,但是只有一段完全扫描完
        if (q[i] < q[j])tmp[u++] = q[i++];
        else tmp[u++] = q[j++];
    }

    //处理未处理完的另一段
    while (i <= mid)tmp[u++] = q[i++];
    while (j <= r)tmp[u++] = q[j++];

    for (int k = 0, m = l; k < u; k++, m++)//将辅助空间的序列还原至原空间
        q[m] = tmp[k];
}

int main() {
    int n;
    cin >> n;

    for (int i = 0; i < n; i++)cin >> q[i];//读入
    merge_sort(0, n - 1);//排序
    for (int i = 0; i < n; i++)cout << q[i] << " ";//输出

    return 0;
}

利用归并排序求逆序对:

逆序对指的是排在后面的数小于排在前面的数,例如:132中,3和2就是一个逆序对。

输入格式:

第一行:n,代表序列长度。

第二行:序列。

输出格式:

输出逆序对数量即可。

思路:

利用归并排序的合并左右两边的步骤中求出逆序对。 

当q[i]>q[j]时,与q[j]构成逆序对的所有数为q[i]~q[mid]。

由于指针指向的数大于指针扫过了的数,所以q[l]~q[i-1]都是小于q[j]的,不与q[j]构成逆序对;

由于两侧都是有序排列的,所以q[mid+1]~q[j-1]都是小于q[j]的,不与q[j]构成逆序对,q[i]~q[mid]都是大于q[j]的,与q[j]够成逆序对。此时逆序对的数量加上mid-i+1。

当合并操作完成时,我们可以不重不漏的求出这个范围内的所有逆序对。

注意存储逆序对的数量要开long long。

代码如下:

#include
using namespace std;

const int N = 1e5 + 10;
int q[N], tmp[N];
long long res = 0;

void merge(int l, int r) {
    if (l == r)return;

    int mid = (l + r) >> 1;

    merge(l, mid), merge(mid + 1, r);

    int i = l, j = mid + 1, u = 0;
    while (i <= mid && j <= r) {
        //合并的过程中求逆序对,也是和归并排序代码唯一的不同
        if (q[j] < q[i]) { res += (mid - i + 1); tmp[u++] = q[j]; j++; }
        else { tmp[u++] = q[i]; i++; }
    }

    while (i <= mid)tmp[u++] = q[i++];
    while (j <= r)tmp[u++] = q[j++];

    for (int k = 0; k < u; k++) {
        q[l++] = tmp[k];
    }
}

int main() {
    int n;
    cin >> n;

    for (int i = 0; i < n; i++)cin >> q[i];

    merge(0, n - 1);

    cout << res;
    return 0;
}

你可能感兴趣的:(c++,算法,排序算法,蓝桥杯,数据结构)