169 lines
No EOL
3.7 KiB
Text
169 lines
No EOL
3.7 KiB
Text
---
|
|
id: custom-cpp-stl
|
|
title: "C++ STL with Custom Comparators"
|
|
author: Siyong Huang, Benjamin Qi
|
|
prerequisites:
|
|
- Silver - Sorting with Custom Comparators
|
|
- Silver - Introduction to Ordered Sets
|
|
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;
|
|
``` |