归并排序 -模板题
思路:
1.确定分界点 mid = l + r >> 2
2.递归排序Left、Right部分
3.使用双指针算法归并排序Left、Right部分
代码:
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],tmp[N];
void merge_sort(int *a , int l, int r)
{
//如果子序列小于等于1,则返回
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]) tmp[k++] = a[i++];
else tmp[k++] = a[j++];
while(i <= mid) tmp[k++] = a[i++];
while(j <= r) tmp[k++] = a[j++];
//在放回原数组
for(i = l, j = 0; i <= r; i++, j++)
a[i] = tmp[j];
}
int main(void)
{
int n;
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
merge_sort(a,0,n-1);
for(int i = 0; i < n; i++) cout << a[i] << ' ';
return 0;
}
逆序对的数量
思路:
1.总的数量等于 Left边中逆序对的数量、Right边中逆序对的数量、Left、Right两边的元素共同组成的逆序对的数量
2.如何求算Left、Right两边的元素共同组成的逆序对的数量?
- 考虑Right中元素被放入tmp数组中,即表示此元素小于Left边中任意元素,所以有 ans += mid - i + 1;
代码:
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long int LL;
const int N = 100010;
int a[N],tmp[N];
LL merge_sort(int *a , int l, int r)
{
//如果子序列小于等于1,则返回
if(l >= r) return 0;
int mid = l + r >> 1;
//递归排序
LL res = 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])
{
tmp[k++] = a[i++];
}
else
{
res += (LL)mid - i + 1;
tmp[k++] = a[j++];
}
while(i <= mid) tmp[k++] = a[i++];
while(j <= r) tmp[k++] = a[j++];
//在放回原数组
for(i = l, j = 0; i <= r; i++, j++)
a[i] = tmp[j];
return res;
}
int main(void)
{
int n;
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
LL ans = merge_sort(a,0,n-1);
cout << ans << endl;
return 0;
}