归并算法及求逆序对例题
归并算法及求逆序对例题
归并算法
思路
- 首先先确定分界点mid,分界点为mid = (l + r) /2,也就是整个数列的中间,将整个数列通过这个分界点一分为二。
- 分别递归左右两个序列,将两个无序序列变为有序序列
- 再分别将左右两个有序序列合并为一个有序序列
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
解题思路
-
首先先将整个数列一分为二
-
一共可能有三种情况,两个数字都在左边的数组;两个数字都在右边的数组;一个数字在左边的数组,一个数字在右边的数组。
-
都在左边的数量一共就是归并排序的数量也就是guibing(q, l, mid);
-
都在右边的数量一共就是归并排序的数量也就是guibing(q, mid + 1, r);
-
一左一右的情况的数量就是:右边每个数字的逆序对成立条件的总和
(每个数字的数量就是 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;
}