在程序设计中,通常会使用到以下这些排序算法,这里把它们分为三类:
1.选择排序、插入排序、冒泡排序
2.堆排序、归并排序、快速排序
3.计数排序、基数排序、桶排序
$$ 前两类是基于比较的排序算法,对 n 个元素进行排序时$$ $$ 若元素比较大小的时间复杂度为O(1),则第一类排序算法的时间复杂度为O(n^2) $$ $$ 第二类排序算法的时间复杂度为 O(n logn)。实际上,基于比较的排序算法的时间复杂度下界为 O(nlogn) $$ $$ 因此堆排序、归并排序、快速排序已经是时间复杂度最优的基于比较的排序算法。 $$
离散化
离散化,就是当我们只关心数据的大小关系时,用排名代替原数据进行处理的一种预处理方法。离散化本质上是一种哈希,它在保持原序列大小关系的前提下把其映射成正整数。当原数据很大或含有负数、小数时,难以表示为数组下标,一些算法和数据结构(如BIT)无法运作,这时我们就可以考虑将其离散化。
实际上,离散化可以用STL较简单地完成。
例如,现在我们有序列A=[10, 23, 35, 3, -40, 3]。我们先复制一个同样的序列:
int C[MAXN];
memcpy(C, A, sizeof(A));
排序,去重:
sort(C, C + n);
int l = unique(C, C + n) - C; // l为不重复元素的数量
std::unique()的返回值是一个迭代器(对于数组来说就是指针了),它表示去重后容器中不重复序列的最后一个元素的下一个元素。所以可以这样作差求得不重复元素的数量。现在我们有C=[-40, 3, 10, 23, 35]。
再用一个数组,储存A中每个元素在C中的排名:
int L[MAXN];
for (int i = 0; i < n; ++i)
L[i] = lower_bound(C, C + l, A[i]) - C + 1; // 二分查找
这样我们就实现了原序列的离散化。得到L = [3,4,5,2,1,2]。
$$ 因为排序和 n 次二分查找的复杂度都是 O(n logn),所以离散化的时间复杂度也是O(n log n)。$$ 完整代码很短:
int C[MAXN], L[MAXN];
// 在main函数中...
memcpy(C, A, sizeof(A)); // 复制
sort(C, C + n); // 排序
int l = unique(C, C + n) - C; // 去重
for (int i = 0; i < n; ++i)
L[i] = lower_bound(C, C + l, A[i]) - C + 1; // 查找
$$ 离散化也不一定要从小到大排序,有时候也需要从大到小 $$
$$ 这时在排序和查找时相应地加上 greater<int>() 就可以了 $$
例题:程序自动分析
tag:离散化,并查集,排序
思路:对于"变量相等"的约束条件,我们将其放入同一个集合里面,对于"变量不相等"的约束条件,我们看两个元素是否在同一个集合里面(根相同),如果在同一个集合里面,无法满足既相等要不相等的互斥条件,所以我们要输出NO,全部都不冲突的话,我们输出YES。但是我们要注意:
要先把所有的"变量相等"的数据排在前面,最后判断不相等的情况,其次,因为x和y的数据范围太大,无法开那么大的fa数组,所以我们要对数据离散化处理。具体代码如下:
#include <bits/stdc++.h>
#define i64 long long
constexpr int N = 1e6;
int fa[N];
int find(int x) {
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
void merge(int x, int y) {
fa[find(x)] = find(y);
}
struct node {
int x, y, opt;
};
bool cmp(node a, node b) {
return a.opt > b.opt;
}//排序
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
int n;
std::cin >> n;
std::vector<node> a(n + 1);
std::vector<int> POS;
std::memset(fa, 0, sizeof fa);
for (int i = 1; i <= n; i++) {
std::cin >> a[i].x >> a[i].y >> a[i].opt;
POS.emplace_back(a[i].x);
POS.emplace_back(a[i].y);
}
std::sort(POS.begin(), POS.end());
POS.erase(std::unique(POS.begin(), POS.end()), POS.end());
for (int i = 1; i <= n; i++) {
a[i].x =
std::lower_bound(POS.begin(), POS.end(), a[i].x) - POS.begin();
a[i].y =
std::lower_bound(POS.begin(), POS.end(), a[i].y) - POS.begin();
}//离散化
int cnt = (int)POS.size();
for (int i = 1; i <= cnt; i++) {
fa[i] = i;
}//初始化
std::sort(a.begin() + 1, a.end(), cmp);
bool f = false;
for (int i = 1; i <= n; i++) {
if (a[i].opt == 1) {
merge(a[i].x, a[i].y);
} else {
if (find(a[i].x) == find(a[i].y)) {
f = true;
break;
//冲突
}
}
}
if (f) {
std::cout << "NO\n";
} else {
std::cout << "YES\n";
}//注意大小写
}
return 0;
}