--- id: custom-cpp-stl title: "C++ Sets with Custom Comparators" author: Siyong Huang, Benjamin Qi prerequisites: - sorting-custom - intro-ordered description: "?" frequency: 1 --- Covers all of this material.
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 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 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 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 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 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 v(cmp);` instead. ## Functors Probably less confusing than the method above. ```cpp #include 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 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 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`. Similarly, overloading `>` automatically generates the functor [`greater`](https://en.cppreference.com/w/cpp/utility/functional/greater). We can use this to store a set in reverse order. ```cpp #include 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> 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> a; map> b; priority_queue,greater> c; ```