在 C++ 中创建一个包含不同类型事件的最小优先级队列

Posted

技术标签:

【中文标题】在 C++ 中创建一个包含不同类型事件的最小优先级队列【英文标题】:Create a Min Priority Queue contain different types of event in C++ 【发布时间】:2016-07-29 11:01:30 【问题描述】:
class Event

    // Overloading the comparison operators
    friend bool operator < (const Event& e1, const Event& e2);
    friend bool operator == (const Event& e1, const Event& e2);

public:
    Event() ;
    enum EvtType arrival_1, arrival_2, arrival_3, arrival_4, arrival_5, arrival_6;
    Event(EvtType type, double etime):
        _type(type), _etime(etime) 

    EvtType get_Type()
    
       return _type;
    

    double get_time()
    
       return _etime;
    

protected:
    EvtType _type;
    double _etime;
;



bool operator < (const Event& e1, const Event& e2)

return e2._etime < e1._etime;


bool operator == (const Event& e1, const Event& e2)

     if(e1._etime != e2._etime)return false;
     if(e1._type == (Event::arrival_2 && Event::arrival_3 &&    Event::arrival_4 && Event::arrival_5 && Event::arrival_6)) return true;
     return false;



priority_queue <Event> FEL;

我创建了一个名为“Event”的类,其中包含几种类型的事件和发生的时间。在此之后,我想创建一个优先级队列“FEL”来包含这些事件及其时间。但是,一般来说,优先级队列总是对事件库的所有最大值进行排序。

如何根据最小值对这些事件进行排序,这样当我调用 FEL.top() 时,我会得到时间最短的事件。

我试图通过使用 bool 运算符来解决这个问题。但是它仍然有问题。任何人请帮助解决此问题将不胜感激。

非常感谢

【问题讨论】:

std::priority_queue 允许您传递任何比较器函数。它可以是默认的std::less,也可以是像std::greater 这样的其他标准比较器,甚至可以是自定义函数或可调用对象。 有没有办法使用bool操作符来设置,所以每次调用FEL.top()时,都会自动获取时间最短的事件?请给我演示一些代码。 是的,通过为您的 Event 类实现 operator&lt; 函数。这就是你所要做的。 ***.com/questions/16111337/… 【参考方案1】:

std::priority_queue 容器适配器是一个最大队列结构。它利用“较少”比较器以 最大 项始终排在第一位的方式对排队的项进行排序。因此,如果您想首先获得 最小 项,则需要一个与您最初看起来自然相反的比较器。

举个简单的例子,假设您有一个包含int 值的向量,并且您希望它们的优先级最大最小。这是std::priority_queue&lt;int&gt; 的自然默认操作操作。它使用std::less&lt;int&gt; 来确定项目的顺序(哪些在前面,哪些在后面),并在给定这些结果的情况下确保最大的首先出现在队列中。考虑以下示例,它创建了两个int 队列,一个使用std::less&lt;int&gt;,另一个使用std::greater&lt;int&gt; 进行比较:

#include <iostream>
#include <algorithm>
#include <queue>
#include <random>

int main()

    std::random_device rd;
    std::mt19937 rng(rd());
    std::uniform_int_distribution<> dist(1,10);

    std::priority_queue<int, std::vector<int>, std::less<int>> q1;
    std::priority_queue<int, std::vector<int>, std::greater<int>> q2;

    for (int i=0; i<20; ++i)
    
        int value = dist(rng);
        q1.push(value);
        q2.push(value);
    

    std::cout << "q1: ";
    for (; !q1.empty(); q1.pop())
        std::cout << q1.top() << ' ';
    std::cout << '\n';

    std::cout << "q2: ";
    for (; !q2.empty(); q2.pop())
        std::cout << q2.top() << ' ';
    std::cout << '\n';

输出(可变)

q1: 10 10 8 8 8 7 6 6 5 5 5 4 4 4 3 3 3 2 1 1 
q2: 1 1 2 3 3 3 4 4 4 5 5 5 6 6 7 8 8 8 10 10 

如您所见,在确定排序时使用“更大”比较器作为其较少操作的队列会交付您所寻求的。我们只需要将这样的东西放入您的队列及其Event 类型


您需要一个与默认顺序相反的比较器:

#include <iostream>
#include <algorithm>
#include <queue>

class Event

public:
    enum EvtType  arrival_1, arrival_2, arrival_3, arrival_4, arrival_5, arrival_6 ;

    Event(EvtType type = arrival_1, double etime = 0.0)
        : _type(type)
        , _etime(etime)
    

    EvtType get_Type() const  return _type; ;
    double get_Time() const  return _etime; 

protected:
    EvtType _type;
    double _etime;
;

struct EventLess

    bool operator()(const Event& lhs, const Event& rhs) const
    
        return (lhs.get_Time() > rhs.get_Time());
    
;

int main()


    std::priority_queue<Event, std::vector<Event>, EventLess> q;
    q.push(Event(Event::arrival_1, 3.0));
    q.push(Event(Event::arrival_2, 2.0));
    q.push(Event(Event::arrival_3, 1.0));
    q.push(Event(Event::arrival_1, 1.0));
    q.push(Event(Event::arrival_2, 2.0));
    q.push(Event(Event::arrival_3, 3.0));

    while (!q.empty())
    
        const Event& e = q.top();
        std::cout << e.get_Type() << ' ' << e.get_Time() << '\n';
        q.pop();
    

输出

2 1
0 1
1 2
1 2
0 3
2 3

注意时间值(秒)从小到大排列。这是因为我们的比较器EventLess 说“时间较大的项目比时间较小的项目‘少’”,并且队列自然地将它们推到队列的下方,而不是将它们提升到顶部。使这项工作发挥作用的原因很简单:

struct EventLess

    bool operator()(const Event& lhs, const Event& rhs) const
    
        return (lhs.get_Time() > rhs.get_Time());
    
;

这里我们告诉调用者(队列适配器)给定两个元素,一个具有更大时间值的元素应该被认为“小于”具有更小的时间值的元素。然后队列将项目从大到小排序。

我认为您了解自定义比较的必要性。我只是认为您不了解std::priority_queue 的工作原理。这是一个最大队列。你只需要说服它你对max 的定义是不同的。

【讨论】:

非常感谢。这很有帮助。现在我对优先队列有了更多的了解。 @Rocky 如果这回答了您的问题,请使用勾号将其标记为已接受的答案。如果没有,请说明人们还能做些什么来提供帮助。【参考方案2】:

首先,您不能仅根据显示的代码创建std::priority_queue&lt;Event&gt;Event 没有实现 &lt; 运算符,而 std::priority_queue&lt;Event&gt; 需要它。

您要么定义了 &lt; 运算符,但它未包含在显示的代码中,要么您必须已经将一个可选的比较器类传递给现有的 std::priority_queue,它为所有 @987654327 指定了严格的弱排序@s.

在任何一种情况下,只需更改适当的比较函数,即可按照您想要的顺序比较您的Events。

【讨论】:

【参考方案3】:

您可以向std::priority_queue 提供自定义比较器类型参数。 但在我们这样做之前,让我们为您的 Event 类定义运算符 &gt;

bool Event::operator>(Event const& other) 
    return _etime > other._etime;

您也可以按照与其他运算符相同的方式定义它。现在,您的队列类型变为:

std::priority_queue<Event, std::vector<Event>, std::greater<Event>> FEL;

这将具有将具有最低时间戳_etimeEvent 对象放在顶部的效果。

【讨论】:

以上是关于在 C++ 中创建一个包含不同类型事件的最小优先级队列的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中创建包含不同类型的字典类型?

有没有一种简单的方法可以在 C++ 中创建一个最小堆?

如何在 C# 中创建包含不同类型的字典

在 C++ 中的类中创建类对象的动态数组

如何在java中的每个arraylist中创建具有不同类型对象的arraylist数组?

在 C++ 中创建/打开事件并检查它们是不是被触发