0
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;

I have create a class called "Event" which contain several types of event and time to occur. After this, I would like to create a priority queue "FEL" to contain these events and their times. However, in general priority queue always sort the event base all max value.

How can I sort these event based on min value, so that when i call the FEL.top(), I will get the event with smallest time.

I have tried to solve this by using bool operator. But It still has a problem. Anyone please helps to fix this would be grateful.

Thank You very much

Rocky
  • 15
  • 4
  • [`std::priority_queue`](http://en.cppreference.com/w/cpp/container/priority_queue) allows you to pass along any comparator function. It can be the default [`std::less`](http://en.cppreference.com/w/cpp/utility/functional/less), or another lstandard comparator like [`std::greater`](http://en.cppreference.com/w/cpp/utility/functional/greater), or even a custom function or callable object. – Some programmer dude Jul 29 '16 at 11:10
  • Is there anyway to use bool operator to set it, so every time when i call FEL.top(), i will obtain the event with smallest time automatically ? Please demonstrate me some codes. – Rocky Jul 29 '16 at 11:16
  • Yes, by implementing an `operator<` function for your `Event` class. That's all you have to do. – Some programmer dude Jul 29 '16 at 11:17
  • http://stackoverflow.com/questions/16111337/declaring-a-priority-queue-in-c-with-a-custom-comparator – sameerkn Jul 29 '16 at 11:20

3 Answers3

1

The std::priority_queue container adapter is a max-queue construct. It utilizes a "less" comparator to sort the queued items in a way where the maximum item is always first. Thus, if you want to have the smallest items first, you need a comparator that does the opposite of what may first seem natural to you.

A quick example, suppose you had a vector of int values and you wanted them prioritized largest to smallest. This is the natural, default operational action of std::priority_queue<int>. it uses std::less<int> to determine the order of the items (which come before, which come after), and given those outcomes, ensures the largest appears first in the queue. Consider the following example, which makes two int queues, one which uses std::less<int> the other std::greater<int> for comparison:

#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';
}

Output (varies)

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 

As you can see, a queue that uses a "greater" comparator for its less-op when determining ordering delivers what you seek. We just need to fit such a thing into your queue and its Event type


You need a comparator that does the opposite of the default ordering:

#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();
    }
}

Output

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

Note the time value (the second) is ordered smallest to largest. This is because our comparator EventLess says "items with larger times are 'less' than items with smaller times", and the queue naturally pushes those down the queue rather than promoting them to the top. What makes this work is simply this:

struct EventLess
{
    bool operator()(const Event& lhs, const Event& rhs) const
    {
        return (lhs.get_Time() > rhs.get_Time());
    }
};

Here we're telling the caller (the queue adapter) that given two elements, the one with a greater time value should be considered "less" than something with a smaller time value. The queue then orders the items largest to smallest.

I think you understand the need for custom comparison. I just don't think you understood how the std::priority_queue works. It's a max-queue. You just have to convince it your definition of max is something different.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • Thank you very much. This is very helpful. Now I understand more about priority Queue. – Rocky Jul 29 '16 at 13:26
  • @Rocky If this answered your question, then please mark it as the accepted answer using the tick symbol. If it did not, then please clarify what else people can do to help. – underscore_d Jul 29 '16 at 15:47
0

You cannot create a std::priority_queue<Event> in the first place, based solely on the shown code. Event does not implement the < operator, which std::priority_queue<Event> requires.

You either have the < operator defined, but it was not included in the shown code, or you must be already passing an optional comparator class to your existing std::priority_queue, that specifies strict weak ordering for all the Events.

In either case, simply change the appropriate comparison function to compare your Events in the order you want.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
0

You can supply a custom comparator type parameter to std::priority_queue. But before we do that let's define the operator > for your Event class:

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

You can also define it in the same fashion you did for the other operators. Now, your queue's type becomes:

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

This will have the effect to put the Event object with the lowest timestamp _etime on top.

Rerito
  • 5,886
  • 21
  • 47