Leetcode 347 -- 优先队列的坑

题目描述

前 k 个高频元素

坑点

  1. \(C++\) 中,可以在 \(Class\) 中再定义一个 \(Class\)
  2. 对于优先队列的排序,我们要反过来考虑!例如我们使用 \(less<int>\) 排序时,我们是希望队头是最小的元素,但是恰恰相反!队头是最大的元素。对于我们自定义的排序规则也是如此。
  3. 另外,比较规则我们传入的是类型,因为它是作为模板参数的!!!

比较参数

在下面的例子中,我们虽然可以将 \(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\) 指针!
其实上面的回答从另一方面论证了:我们不可以在重载类的 < 函数并作为模板的比较类型传入这个类,因为类的成员函数必须被类的实例调用(静态成员函数除外),而在这里我们显然是没有类的实例的,所以说拿什么调用它呢?
因此说正确的方法有两种:

  1. 仿函数
  2. 载类内部 \(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;
}
posted @ 2022-11-15 10:47  光風霽月  阅读(50)  评论(0编辑  收藏  举报