C++ 自定义比较器
重载操作符 <
实际上是对自定义的 struct,重写它的 operator < 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| struct Str{ string s; bool operator < (const Str &str) const { return s.length() < str.s.length(); } };
int main() { vector<Str> vec; for (int i = 0; i < 5; ++i) { Str s; cin >> s.s; vec.push_back(s); } sort(vec.begin(), vec.end()); return 0; }
|
函数比较器
可以通过写一个外部的比较器函数,实现 < 方法:
使用这种方式常常用在如下情形:
-
比较内置类型
-
不能修改需要比较的运算符
-
除了类型自定义的比较方式以外的比较方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| bool cmp(const string &s1, const string &s2) { return s1.length() < s2.length(); }
int main() { vector<string> vec; for (int i = 0; i < 5; ++i) { string s; cin >> s; vec.push_back(s); } sort(vec.begin(), vec.end(), cmp); return 0; }
|
函数对象结构体比较器
所谓函数对象,是实现了 operator()
的类或者结构体,可以用这个对象来替代函数作为比较器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct Cmper{ bool operator() (const string &s1, const string &s2) { return s1.length() < s2.length(); } };
int main() { vector<string> vec; for (int i = 0; i < 5; ++i) { string s; cin >> s; vec.push_back(s); } sort(vec.begin(), vec.end(), Cmper()); return 0; }
|
但是和第一个略有不同的是,方法末尾的 const
修饰可有可无。这是因为方法末尾的 const
代表了不会修改结构体内部变量的值,显然和我们要用到的功能毫无关系。
1 2 3
| bool operator() (const string &s1, const string &s2) {} bool operator() (const string &s1, const string &s2) const {}
|
最后要注意的是,传给 sort
的应当是一个结构体对象而不是结构体名称。
1 2 3 4
| sort(vec.begin(), vec.end(), Cmper);
sort(vec.begin(), vec.end(), Cmper());
|
C++ 优先队列自定义比较
重载运算符
成员函数写法
1 2 3 4 5 6 7 8 9 10 11 12
| struct Node { int x, y; bool operator<(Node &a) const { return y < a.y; } bool operator>(Node &a) const { return y > a.y; } };
priority_queue<Node, vector<Node>, less<Node>>A; priority_queue<Node, vector<Node>, greater<Node>> B;
|
1 2 3 4 5 6 7
| struct Node { int x, y; bool operator<(Node &a) const { return y < a.y; } }; priority_queue<Node>A;
|
1 2 3 4 5 6 7
| struct Node { int x, y; bool operator<(Node &a) const { return y > a.y; } }; priority_queue<Node> B;
|
友元函数写法
1 2 3 4 5 6 7 8 9 10 11 12
| struct Node { int x, y; friend bool operator<(const Node &a, const Node &b) { return a.x < b.x; } friend bool operator>(const Node &a, const Node &b) { return a.x > b.x; } };
priority_queue<Node> A; priority_queue<Node, vector<Node>, greater<Node> > B;
|
1 2 3 4 5 6 7 8
| struct Node { int x, y; friend bool operator<(const Node &a, const Node &b) { return a.x < b.x; } };
priority_queue<Node> A;
|
1 2 3 4 5 6 7
| struct Node { int x, y; friend bool operator<(const Node &a, const Node &b) { return a.x > b.x; } }; priority_queue<Node> B;
|
函数对象比较器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct Node { int x, y; };
struct cmp { bool operator()(Node &a,Node &b) { return a.x > b.x; } };
struct cmp1 { bool operator()(Node &a,Node &b) { return a.x < b.x; } };
priority_queue<Node, vector<Node>, cmp1> A; priority_queue<Node, vector<Node>, cmp> B;
|
自定义函数比较器
如果想要用升序排列怎么办?先看一下优先队列的定义
1
| priority_queue<Type, Container, Functional>
|
其中 Type 就是数据类型,Container 就是容器类型( Container 必须是用数组实现的容器,比如 vector, deque 等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。
如果传入的是int类型,我们可以用👇定义一个升序优先队列
1
| priority_queue <int,vector<int>,greater<int>> pq;
|
如果要定义一个降序优先队列(等同于默认的不写 Container , Functional 的方式),可以使用这种方法:
1
| priority_queue <int,vector<int>,less<int>> pq;
|
其中greater
和less
是std
实现的两个仿函数
如果不想用greater
和less
,可以使用自定义的比较方法:
1 2
| auto comp = []( int a, int b ) { return a > b; }; priority_queue< int , vector<int>, decltype(comp)> pq(comp);
|
问题来了,为什么初始化pq
的时候还要传comp
进去?
按照我们熟悉的sort
函数的经验,sort
使用lambda表达式定制排序时,可以这样写:
1
| sort (vec.begin(), vec.end(), [](int a, int b) { return a < b; });
|
比着葫芦画瓢,把priority_queue
写成👇却不行。
1
| priority_queue< int , vector<int>, [](int a, int b) { return a < b; }> pq;
|
为什么会出现这种情况,这就需要看一下priority_queue
的构造函数:
1 2
| explicit priority_queue( const Compare& compare = Compare(), const Container& cont = Container() );
|
可以看到,如果我们构造时,不指定特定的compare
对象,那么就用typename Compare
的默认构造函数构造一个,然而lambda表达式的匿名类型是没有默认构造函数的,所以想要正确初始化这个优先队列,还得在构造函数里再把lambda表达式本身传进去。
优先队列自定义比较总结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| class student { public: int age; string name;
friend bool operator<(const student& a, const student& b) { return a.age < b.age; } };
struct mycmp { bool operator()(const student& a, const student& b) { return a.age < b.age; } };
bool cmpfunc(const student& a, const student& b) { return a.age < b.age; }
priority_queue<student> que1;
priority_queue<student, vector<student>, mycmp> que2;
auto cmp = [](const student& a, const student& b) { return a.age < b.age; };
priority_queue<student, vector<student>, decltype(cmp)> que4(cmp);
priority_queue<student, vector<student>, function<bool(const student&, const student&)>> que5(cmp);
priority_queue<student, vector<student>, function<bool(const student&, const student&)>> que6(cmpfunc);
function<bool(const student&, const student&)> func(cmpfunc); priority_queue<student, vector<student>, function<bool(const student&, const student&)>> que7(func);
|
队列节点是指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct Node { int x, y; }; struct cmp { bool operator() (Node const *n1, Node const *n2) { return n1->x < n2->x; } }; struct cmp1 { bool operator() (Node const *n1, Node const *n2) { return n1->x > n2->x; } };
priority_queue<Node*, vector<Node*>, cmp()> A; priority_queue<Node*, vector<Node*>, cmp1()> B;
|