归并算法及求逆序对例题

归并算法及求逆序对例题

归并算法

思路


  1. 首先先确定分界点mid,分界点为mid = (l + r) /2,也就是整个数列的中间,将整个数列通过这个分界点一分为二。
  2. 分别递归左右两个序列,将两个无序序列变为有序序列
  3. 再分别将左右两个有序序列合并为一个有序序列

​ 3.1 首先先将两个指针i,j分别指向两个序列中的最小值(也就是两个序 列的最左边)

​ 3.2然后分别比较i指针所指的数和j指针所指的数,并将两个数中较小的 数放入一个临时数组tmp,并将放入数对应的指针向后移动,重新 进行比较i和j所指数字,(如果i指针所指数字进入tmp,那就将i指 针向后移动一位,重新和j比较)

​ 3.3 循环这个过程知道两个数组中有一个数组全部排入tmp中 ,然后将 另一个数组中剩余的数组全部接入tmp

代码如下

#include <iostream>

using namespace std;

const int N = 100010;

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

void guibing(int q[], int l, int r){
    
    if(l == r) return;
    
    int mid = (l + r) / 2;
    
    guibing(q, l, mid);
    guibing(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 ++];
    
    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", &a[i]);
    
    guibing(a, 0 ,n - 1);
    
    for(int i = 0; i < n; i++) printf("%d ", a[i]);
}

逆序对数量例题

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

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

输入格式

第一行包含整数 nn,表示数列的长度。

第二行包含 nn 个整数,表示整个数列。

输出格式

输出一个整数,表示逆序对的个数。

数据范围

1≤n≤1000001≤n≤100000,
数列中的元素的取值范围 [1,109][1,109]。

输入样例:

6
2 3 4 5 6 1

输出样例:

5


解题思路

  1. 首先先将整个数列一分为二

  2. 一共可能有三种情况,两个数字都在左边的数组;两个数字都在右边的数组;一个数字在左边的数组,一个数字在右边的数组。

  3. 都在左边的数量一共就是归并排序的数量也就是guibing(q, l, mid);

  4. 都在右边的数量一共就是归并排序的数量也就是guibing(q, mid + 1, r);

  5. 一左一右的情况的数量就是:右边每个数字的逆序对成立条件的总和

    (每个数字的数量就是 mid - i + 1)用循环进行计算。

代码如下

#include <iostream>

using namespace std;

typedef long long LL;

const int N = 100010;

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

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



    if(l == r) return 0;

    int mid = (l + r) /2;

    LL num = guibing(q, l, mid) + guibing(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 {
            num += mid - i + 1;
            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];

    return num;
}

int main(){

    scanf("%d", &n);

    for(int i = 0; i < n; i ++) scanf("%d" ,&q[i]);

    cout << guibing(q, 0, n - 1) << endl;

    return 0;

}


posted @ 2022-10-09 09:47  骁峰  阅读(47)  评论(0编辑  收藏  举报