Leetcode 347 -- 优先队列的坑
题目描述
坑点
- 在 \(C++\) 中,可以在 \(Class\) 中再定义一个 \(Class\)
- 对于优先队列的排序,我们要反过来考虑!例如我们使用 \(less<int>\) 排序时,我们是希望队头是最小的元素,但是恰恰相反!队头是最大的元素。对于我们自定义的排序规则也是如此。
- 另外,比较规则我们传入的是类型,因为它是作为模板参数的!!!
比较参数
在下面的例子中,我们虽然可以将 \(MyCmp1,2,3\) 传入优先队列作为模板参数(因为这的确是正确的形式),但是却不能进行操作(\(push\)....)。
首先我们要明白一点!当我们在 \(class\) 内部重载属于这个 \(class\) 的运算符时,运算符的个数是要少一个的!
就比如加法需要两个操作数,在 \(class\) 外面重载时,我们需要显示的指定这两个操作数,但是如果我们要在 \(class\) 内部重载,由于函数自带一个 \(this\) 指针,这个 \(this\) 指针一般作为隐式的最左侧的操作数(第一操作数),因此我们只能显示的指定一个操作数。
注意编译器是禁止我们在重载时修改操作数个数的。 因此说如果你在 \(class\) 内显示指定两个操作数,编译器就会报错。
以下便是我们如果操作 \(q2\) 时 \(MyCmp2\) 的报错信息。
a.cpp:16:10: error: 'bool MyCmp2::operator<(const int&, const int&)' must have exactly one argument
16 | bool operator <(const int &v1, const int &v2) {
那你可能会问,如果我不用 \(this\) 指针那他是不是就不存在了?
答案是:只要是在 \(class\) 中定义的函数,\(this\) 指针永远存在!
为什么呢?会想你调用成员函数的方式,是不是必须得通过.
或者->
来调用,而.
或者->
的前面得有一个成员对象吧!既然有了成员对象,自然也就有了指向他的 \(this\) 指针!
其实上面的回答从另一方面论证了:我们不可以在重载类的<
函数并作为模板的比较类型传入这个类,因为类的成员函数必须被类的实例调用(静态成员函数除外),而在这里我们显然是没有类的实例的,所以说拿什么调用它呢?
因此说正确的方法有两种:
- 仿函数
- 载类内部 \(friend\) 一个外部重载的
<
函数。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
struct MyCmp1 {
int val;
bool operator<(const MyCmp1 &r) {
return this->val < r.val;
}
};
struct MyCmp2 {
bool operator <(const int &v1, const int &v2) {
return v1 < v2;
}
};
class MyCmp3 {
public:
int val;
bool operator()(const int &val) {
return this->val < val;
}
};
class MyCmp4 {
public:
int val;
bool operator()(const int &v1, const int &v2) {
return v1 < v2;
}
};
int main()
{
priority_queue<int, vector<int>, less<int>> q;
priority_queue<int, vector<int>, MyCmp1> q1;
priority_queue<int, vector<int>, MyCmp2> q2;
priority_queue<int, vector<int>, MyCmp3> q3;
priority_queue<int, vector<int>, MyCmp4> q4;
int a[5] = {1, 5, 3, 2, 7};
for(int i = 0; i < 5; i ++ ) {
q.push(a[i]);
// q1.push(a[i]); // wrong
// q2.push(a[i]); // wrong
// q3.push(a[i]); // wrong
q4.push(a[i]);
}
while(q.size()) { // 7 5 3 2 1
cout << q.top() << ' ';
q.pop();
} cout << endl;
while(q4.size()) { // 7 5 3 2 1
cout << q4.top() << ' ';
q4.pop();
} cout << endl;
return 0;
}
例2
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
// 重载类内的 operator<
struct MyCmp2 {
int val;
bool operator <(const MyCmp2 &v2) const {
return val < v2.val;
}
};
// 重载类外的 operator<
struct MyCmp3 {
int val;
friend bool operator <(const MyCmp3 &v1, const MyCmp3 &v2) {
return v1.val > v2.val;
}
};
// 仿函数
class MyCmp4 {
public:
int val;
bool operator()(const int &v1, const int &v2) {
return v1 < v2;
}
};
int main()
{
priority_queue<MyCmp2, vector<MyCmp2>, less<MyCmp2>> q2;
priority_queue<MyCmp3> q3;
priority_queue<int, vector<int>, MyCmp4> q4;
int a[5] = {1, 5, 3, 2, 7};
for(int i = 0; i < 5; i ++ ) {
MyCmp2 node2 = {a[i]};
MyCmp3 node3 = {a[i]};
q2.push(node2);
q3.push(node3);
q4.push(a[i]);
}
while(q2.size()) { // 7 5 3 2 1
cout << q2.top().val << ' ';
q2.pop();
} cout << endl;
while(q3.size()) { // 7 5 3 2 1
cout << q3.top().val << ' ';
q3.pop();
} cout << endl;
while(q4.size()) { // 7 5 3 2 1
cout << q4.top() << ' ';
q4.pop();
} cout << endl;
return 0;
}