- 分治的思想
- 递归排序[L,mid]和[mid+1,R]直至只有一个元素
- 合并,在合并的过程中,注意temp数组中长度为当前r-l+1,合并成一个有序数组;
#include<iostream>
using namespace std;
const int N = 100010;
int n;
int q[N], temp[N];
void mergesort(int a[], int l, int r) {
if (l >= r)
return;
int mid = l + r >> 1;
int k = 0;
mergesort(a, l, mid);
mergesort(a, mid + 1, r);
int i = l, j = mid + 1;
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 (int h = l,int k=0; h <= r; h++)
a[h] = temp[k++];
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
cin >> q[i];
mergesort(q, 0, n - 1);
for (int i = 0; i < n; i++)
cout << q[i];
return 0;
}
练习:求逆序对的数量
给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。
输入格式
第一行包含整数 n,表示数列的长度。
第二行包含 n 个整数,表示整个数列。
输出格式
输出一个整数,表示逆序对的个数。
数据范围
1≤n≤100000,
数列中的元素的取值范围 [1,109]。
输入样例:
6
2 3 4 5 6 1
输出样例:
5
难度:简单
思路分析:
将数组一分为二,逆序对的数即为左边逆序对的数量加上右边逆序对的数量,再加上左边大于右边的序对个数。
即利用归并排序,在归并排序的基础上增加变量res。左边右边独立的逆序对数利用递归从最开始的一个数再合并可以实现计数,重点是在合并的时候求逆序对。合并时两边已排好序,那么只要出现选中q[j]时表示当前q[i]<q[j],那么i后面到mid前的所有数都小于q[j],即逆序对有mid-i+1个。
注意:
- q[i]<q[j]时才会res计数,等于时不算逆序;
- 注意数据范围应取long long
#include<iostream>
using namespace std;
const int N = 100010;
typedef long long LL;
int n;
LL res = 0;
LL q[N], tem[N];
LL mergesort(int l, int r) {
if (l >= r)
return 0;
int mid = l + r >> 1;
int i = l, j = mid + 1;
res = mergesort(l, mid) + mergesort(mid + 1, r);
int k = 0;
while (i <= mid && j <= r) {
if (q[i] <=q[j])
tem[k++] = q[i++];
else
{
tem[k++] = q[j++];
res += mid - i + 1;
}
}
while (i <= mid)
tem[k++] = q[i++];
while (j <= r)
tem[k++] = q[j++];
for (int k = 0, h = l; h <= r; h++)
q[h] = tem[k++];
return res;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> q[i];
}
cout<<mergesort(0, n - 1);
}