归并排序
1 归并排序算法
归并排序的核心思想:分治
- 确定分界点:
mid = (l + r) / 2
- 递归排序左部分和右部分
- 归并,合二为一
归并的方法:外排
- 辅助数组
help[N]
,i
指向左部分的左边界,j指向右部分的左边界;- 比较
q[i]
与q[j]
的大小,小的放入help数组里;- 如果左部分的没有copy将剩下的copy到help数组内,对右部分做同样的操作
- 最后将help数组中存储的数组copy到原数组内
#include <iostream>
using namespace std;
const int N = 100010;
int n, q[N], tmp[N];
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
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]) 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", &q[i]);
quick_sort(q, 0, n - 1);
for (int i = 0; i < n; i++) printf("%d", q[i]);
}
2 归并排序应用
逆序对数
给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。
数的范围
1≤n≤100000
解决方法
使用归并排序的思想:
假设现在的merge_sort函数可以返回数组中所有的逆序对的个数
归并排序:
1、找数组的中间点mid,将数组分为[l, mid]和[mid + 1, r];
2、递归排序左部分,递归排序右部分
3、合并左右区间
逆序对产生的情况:
1、两个数同时出现在左半边:merge_sort(L, mid)
2、两个数同时出现在右半边:merge_sort(mid + 1, R)
3、一个数在左一个数在右
对于第三种情况,整体的思路:右半边的第一个数,看左半边部分中有多少个比其大,以此类推遍历整个右半边的数
归并排序中的归并过程中,有两个指针i, j分别指向左右部分,谁小会将谁添加到辅助数组内,当q[i] > q[j]时,此时[i, mid]之间的数都大于q[j],这时就会产生
mid -i + 1
个逆序对也就是说,在归并的过程中,当要输出q[j]时,此时给最终的逆序对的结果就加上mid - i + 1即可。逆序对最多的数量:整个数组为逆序是的逆序对最多,最多为n(n-1)/2个。
#include <iostream>
using namespace std;
const int N = 100010;
typedef long long LL;
int n;
int q[N], tmp[N];
LL merge_sort(int l, int r)
{
if (l >= r) return 0;
int mid = l + r >> 1;
LL res = merge_sort(l, mid) + merge_sort(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 (i <= mid) tmp[k++] = q[i++];
while (j <= r) tmp[k++] = q[i++];
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(0, n - 1);
}