This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
usaco-guide/content/4_Silver/Custom_Cpp_STL.mdx
2020-07-16 18:51:57 -04:00

169 lines
3.7 KiB
Text

---
id: custom-cpp-stl
title: "C++ Sets with Custom Comparators"
author: Siyong Huang, Benjamin Qi
prerequisites:
- sorting-custom
- intro-ordered
description: "?"
frequency: 1
---
<resources>
<resource source="fushar" title="Comparison Functions in C++" starred url="http://fusharblog.com/3-ways-to-define-comparison-functions-in-cpp/">Covers all of this material.</resource>
</resources>
<br />
What if we want to use a C++ `set` with the `Edge` struct that was defined in "Sorting with Custom Comparators"?
## Operator Overloading
Works as expected, although you should make sure to include the second `const` or you'll get a compilation error. From the link above:
> [The second const] means you cannot modify member variables of the current object.
```cpp
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int a,b,w;
bool operator<(const Edge& y) const { return w < y.w; }
};
int main() {
int M = 4;
set<Edge> v;
for (int i = 0; i < M; ++i) {
int a,b,w; cin >> a >> b >> w;
v.insert({a,b,w});
}
for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```
## Comparator
```cpp
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int a,b,w;
};
bool cmp(const Edge& x, const Edge& y) { return x.w < y.w; }
int main() {
int M = 4;
set<Edge,bool(*)(const Edge&,const Edge&)> v(cmp);
for (int i = 0; i < M; ++i) {
int a,b,w; cin >> a >> b >> w;
v.insert({a,b,w});
}
for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```
Lambda expressions also work:
```cpp
auto cmp = [](const Edge& x, const Edge& y) { return x.w < y.w; };
int main() {
int M = 4;
set<Edge,bool(*)(const Edge&,const Edge&)> v(cmp);
for (int i = 0; i < M; ++i) {
int a,b,w; cin >> a >> b >> w;
v.insert({a,b,w});
}
for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```
In this case, we can shorten the declaration of `v` by writing `set<Edge,decltype(cmp)> v(cmp);` instead.
## Functors
Probably less confusing than the method above.
```cpp
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int a,b,w;
};
struct cmp {
bool operator()(const Edge& x, const Edge& y) { return x.w < y.w; }
};
int main() {
int M = 4;
set<Edge,cmp> v;
for (int i = 0; i < M; ++i) {
int a,b,w; cin >> a >> b >> w;
v.insert({a,b,w});
}
for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```
We can also use `cmp` like a normal function by adding `()` after it.
```cpp
int main() {
int M = 4;
vector<Edge> v;
for (int i = 0; i < M; ++i) {
int a,b,w; cin >> a >> b >> w;
v.push_back({a,b,w});
}
sort(begin(v),end(v),cmp());
for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
```
## Built-In Functors
Overloading the less than operator (`<`) automatically generates the functor `less<Edge>`. Similarly, overloading `>` automatically generates the functor [`greater<Edge>`](https://en.cppreference.com/w/cpp/utility/functional/greater). We can use this to store a set in reverse order.
```cpp
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int a,b,w;
bool operator>(const Edge& y) const { return w > y.w; }
};
int main() {
int M = 4;
set<Edge,greater<Edge>> v;
for (int i = 0; i < M; ++i) {
int a,b,w; cin >> a >> b >> w;
v.insert({a,b,w});
}
for (Edge e: v) cout << e.a << " " << e.b << " " << e.w << "\n";
}
/* Output:
2 3 10
1 2 9
1 3 7
2 4 3
*/
```
## Other Containers
The following are all valid:
```cpp
set<int,greater<int>> a;
map<int,string,greater<int>> b;
priority_queue<int,vector<int>,greater<int>> c;
```