归并排序算法模板以及运用(逆序对的数量)

1.归并排序题目要求:
给定你一个长度为n的整数数列。
请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。

输入格式
输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在1~10^9范围内),表示整个数列。

输出格式
输出共一行,包含 n 个整数,表示排好序的数列。

数据范围
1 ≤ n ≤ 100000
输入样例
5
3 1 2 4 5
输出样例
1 2 3 4 5

算法基本思想和步骤:
归并排序运用了分治的思想,先递归后归并。
第一步:确定分界点。分界点选为数组的中间值 mid = (l+r)/2.
第二步:递归排序数组的左边与右边。
第三步:归并数组,合二为一。

题目的关键点:
如何使左右数组合二为一?假设两个升序排列的数列分别保存在数组a中间值的左边部分和右边部分中,用一个循环,从前往后依次比较保存在左边和右边中的两个剩余序列里的第一个数,将其中的较小者存到数组temp中,当一个较短的序列存完后,再将较长的序列剩余的部分依次保存到数组temp的末尾。

程序代码:

#include <iostream>
using namespace std;

const int N = 1e6 + 10;
int n, a[N], temp[N];

void merge_sort (int a[], int l, int r)
{
    if(l >= r) return;
    int mid = l + r >> 1;
    
    merge_sort(a, l, mid), merge_sort(a, mid + 1, r);
    
    int i = l, j = mid + 1, k = 0;
    while(i <= mid && j <= r )
    {
        if(a[i] < a[j]) temp[k++] = a[i++];
        else temp[k++] = a[j++];
    }
    while(i <= mid) temp[k++] = a[i++];
    while(j <= r) temp[k++] = a[j++];
    
    for(i = l, j = 0; i <= r; i++, j++)
        a[i] = temp[j];
}
int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i++)  scanf("%d", &a[i]);
    
    merge_sort(a, 0, n-1);
    
    for(int i =0; i < n; i++) printf("%d ", a[i]);
    return 0;
}

2.逆序对的数量题目要求:
给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。

输入格式
第一行包含整数n,表示数列的长度。
第二行包含 n 个整数,表示整个数列。

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

数据范围
1≤n≤100000
输入样例:
6
2 3 4 5 6 1
输出样例:
5

扫描二维码关注公众号,回复: 11408641 查看本文章

算法的基本步骤:
1.对左半区间排序,并求逆序对的个数:merge_sort(l, mid);
2.对右半区间排序,并求逆序对的个数:merge_sort(mid + 1, r);
3.求横跨左右的逆序对的数量。此时,左右区间已经按大小排序,当左区间的某个数大于右区间的某个数时,则左区间该数后面的数则也大于右区间的那个数。可以用 res += mid - i + 1来求解。

程序代码:

#include <iostream>
using namespace std;

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

LL merge_sort(int q[], int l, int r)
{
    if(l >= r)  return 0;
    
    int mid = l + r >> 1;
    LL res = 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])  t[k++] = q[i++];
        else
        {
            t[k++] = q[j++];
            res += mid - i + 1;
        }
    }
    while(i <= mid)  t[k++] = q[i++];
    while(j <= r) t[k++] = q[j++];
    
    for(i = l, j = 0; i <= r; i ++, j ++)
        q[i] = t[j];
        
    return res;
}

int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i ++) cin >> q[i];
    
    cout << merge_sort(q, 0, n - 1) << endl;
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Quorra_chord/article/details/107131659