排序、去重与离散化
1. 排序
1.1 快速排序
1. 快速排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int q[N];
void quick_sort(int q[], int l, int r)
{
if (l >= r) return; // 使得l恒小于等于r
int i = l - 1, j = r + 1, x = q[l + r >> 1]; // 定义双指针和分界点
while(i < j)
{
do i++; while (q[i] < x); // x左边的数字比x小
do j--; while (q[j] > x); // x右边的数字比x大
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j); // 对x左边和右边的区间再进行快排,分界点是j
quick_sort(q, j + 1, r);
}
int main()
{
int n;
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]);
return 0;
}
2. 快排求第k小
#include <bits/stdc++.h>
using namespace std;
int const N = 1e5 +10;
int k, n;
int q[N];
int quick_sort(int l, int r)
{
if (l >= r) return q[l];
int i = l - 1, j = r + 1, x = q[l];
while (i < j)
{
do i++; while (q[i] < x);
do j--; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
if (j >= k - 1) quick_sort(l, j); // 如果j指向的位置大于等于k-1,那么只需要对左半区间进行快排,右半区间无需操作,省去一半的时间
else quick_sort(j + 1, r);
}
int main()
{
cin >> n >> k;
for (int i = 0; i < n ;++i) scanf("%d", &q[i]);
int t = quick_sort(0, n - 1);
cout << t;
return 0;
}
1.2 归并排序
1. 归并排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int tmp[N], q[N];
void merge_sort(int l, int r)
{
if (l >= r) return ;
int mid = (l + r) >> 1;
int i = l, j = mid + 1, k = 0;
merge_sort(l, mid), merge_sort(mid + 1, r);
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 (int i = l, k = 0; i <= r; ++i) q[i] = tmp[k ++];
}
int main()
{
int n;
cin >> n;
for (int i = 0 ; i < n ; ++i)
scanf("%d", &q[i]);
merge_sort(0, n - 1);
for (int i = 0; i < n; ++i) cout << q[i] << " ";
return 0;
}
2. 归并排序求逆序对
#include <bits/stdc++.h>
using namespace std;
int const N = 1e7 + 10;
int q[N], tmp[N];
int n;
double ans = 0; // 记录答案
void merge_sort(int l, int r)
{
if (l >= r) return;
int mid = (l + r) >> 1;
merge_sort(l, mid ), merge_sort(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
{
ans += mid - i + 1; // 从i~mid这段的数字均为逆序对
tmp[k++] = q[j ++];
}
}
while (i <= mid ) tmp[k ++] = q[i ++];
while (j <= r) tmp[k++] = q[j ++];
for (int i = l, k = 0; i <= r; ++i) q[i] = tmp[k ++ ];
}
int main()
{
cin >> n;
for (int i = 0 ; i < n; ++i) scanf("%d", &q[i]);
merge_sort(0, n - 1);
printf("%.0f", ans);
return 0;
}
1.3 自定义排序写法
1. 直接在结构体内重载
#include <bits/stdc++.h>
using namespace std;
struct Range // 按l从小到大排序(return l < R.l;);按l从大到小排序(return l > R.l;) 这句始终不变:(bool operator< (const Range &R)const)
{
int l, r;
bool operator< (const Range &R)const
{
return l < R.l;
}
}range[100];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; ++i)
{
int l, r;
cin >> l >> r;
}
sort(range, range + n, cmp);
return 0;
}
2. 定义cmp函数
#include <bits/stdc++.h>
using namespace std;
struct Range
{
int l, r;
}range[100];
bool cmp(struct Range x, struct Range y)
{
return x.l < y.l; // 按l从小到大排序(x.l < y.l),按l从大到小排序(x.l > y.l)
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; ++i)
{
int l, r;
cin >> l >> r;
}
sort(range, range + n, cmp);
return 0;
}
2. 去重
sort(a, a + cnt);
cnt = unique(a, a + cnt) - a; // cnt为去重后的序列长度
3. 离散化
思想
把一个大的区间S映射到一个小的区间s,映射的原理是:大区间有很多的值没有使用,可以选择把这些值给忽略
板子
1. 离线离散化
void read_discrete()
{
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
char str[5];
scanf("%d%d%s", &query[i].l, &query[i].r, str);
query[i].ans = (str[0] == 'o'? 1: 0);
a[++t] = query[i].l - 1;
a[++t] = query[i].r;
}
sort(a + 1, a + 1 + t);
n = unique(a + 1, a + 1 + t) - a - 1;
}
// main
read_discrete();
for (int i = 1 ; i <= m; ++i)
{
int x = lower_bound(a + 1, a + n + 1, query[i].l - 1) - a;
int y = lower_bound(a + 1, a + n + 1, query[i].r) - a;
}
2. 在线离散化
#include <unordered_map>
unordered_map<int, int> S;
int cnt;
int mapping(int x)
{
if (!S.count(x)) S[x] = ++cnt;
return S[x];
}
// main
for (int i = 0; i < m; ++i)
{
cin >> a >> b;
a = mapping(a), b = mapping(b);
}