C++ C++;优先级队列不符合FIFO顺序

C++ C++;优先级队列不符合FIFO顺序,c++,priority-queue,fifo,C++,Priority Queue,Fifo,我正在使用STL优先级队列收集我自己的类Lettura的对象 //---------LETTURA---------- enum Priority {zero, standard, urgent}; class Lettura{ public: int valore; char sensore; Priority priorita; Lettura(): valore(0),sensore('\0'),priorita(zero){} Lettura(const int val, con

我正在使用STL优先级队列收集我自己的类Lettura的对象

//---------LETTURA----------

enum Priority {zero, standard, urgent};

class Lettura{
public:
int valore;
char sensore;
Priority priorita;

Lettura():  valore(0),sensore('\0'),priorita(zero){}
Lettura(const int val, const char s='\0', const Priority p=zero):  valore(val),sensore(s), priorita(p){}

friend ostream& operator<<(ostream& out, const Lettura & lett);
};
我希望以FIFO顺序使用相同的优先级元素:

top: l5  urgent
top: l1  standard
top: l2  standard
top: l3  standard
top: l4  standard
top: l6  standard
这是我的代码:

int main() {
std::priority_queue<Lettura, std::vector<Lettura>, std::less<Lettura> > coda;

Lettura l1(50,'a',standard);
Lettura l2(50,'b',standard);
Lettura l3(120,'c',standard);
Lettura l4(100,'d',standard);
Lettura l5(30,'e',urgent);
Lettura l6(35,'f',standard);

coda.push(l1);
coda.push(l2);
coda.push(l3);
coda.push(l4);
coda.push(l5);
coda.push(l6);


cout<<"top: "<<coda.top()<<"\n";    coda.pop();
cout<<"top: "<<coda.top()<<"\n";    coda.pop();
cout<<"top: "<<coda.top()<<"\n";    coda.pop();
cout<<"top: "<<coda.top()<<"\n";    coda.pop();
cout<<"top: "<<coda.top()<<"\n";    coda.pop();
cout<<"top: "<<coda.top()<<"\n";    coda.pop();
}
intmain(){
std::优先级队列尾码;
Lettura l1(50,'a',标准);
Lettura l2(50,'b',标准);
Lettura l3(120,'c',标准);
Lettura l4(100,'d',标准);
Lettura l5(30,'e',紧急);
Lettura l6(35,'f',标准);
尾波推力(l1);
尾波推力(l2);
尾波推力(l3);
尾波推力(l4);
尾波推力(l5);
尾波推力(l6);

cout您的代码似乎正常工作,因为您首先获取紧急项目。在基于堆的优先级队列中,没有按插入时间进行子排序,因此您将以未定义的顺序获取具有相同优先级的项目,只是它们将位于具有更高优先级的项目之后。您需要添加一个额外字段,例如“时间投入”队列,并将其与优先级枚举一起使用在比较运算符中。

它似乎是编译器库和C++标准的一个bug。它们打破了PrimRythyQueLe中最大元素的选择算法。


我将准备相应的方案。

这里是一个稳定优先级队列的简单实现

每当队列为空时,它会尝试通过将插入计数器归零来阻止排序耗尽:

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


enum Priority
{
    zero, standard, urgent
};

inline std::ostream& operator <<(std::ostream& os, const Priority& p)
{
    switch (p) {
        case zero:
            return os << "zero";
        case standard:
            return os << "standard";
        case urgent:
            return os << "urgent";
    }
}

class Lettura
{
public:
    int      valore;
    char     sensore;
    Priority priorita;

    Lettura()
        : valore(0)
        , sensore('\0')
        , priorita(zero) {}

    Lettura(const int val, const char s = '\0', const Priority p = zero)
        : valore(val)
        , sensore(s)
        , priorita(p) {}

    friend std::ostream& operator <<(std::ostream& out, const Lettura& lett)
    {
        return out << "{ valore: " << lett.valore << ", sensore: " << lett.sensore << ", priorita: " << lett.priorita
                   << " }";
    }
};


template<class T, class Comp>
struct stable_priority_queue
{
    using counter_type = std::size_t;

    struct Proxy
    {
        Proxy(T&& o, counter_type c)
            : object(std::move(o))
            , insertion_order_(c) {}

        Proxy(const T& o, counter_type c)
            : object(o)
            , insertion_order_(c) {}

        T            object;
        counter_type insertion_order_;
    };

    struct ProxyComp
    {
        bool operator ()(Proxy const& l, Proxy const& r) const
        {
            if (major_order_(l.object, r.object))
                return true;
            if (major_order_(r.object, l.object))
                return false;
            return minor_order_(l.insertion_order_, r.insertion_order_);
        }

        Comp           major_order_;
        std::greater<> minor_order_;
    };


    decltype(auto) push(T item)
    {
        return queue_.emplace(std::move(item), counter_++);
    }

    T const& top() const
    {
        return queue_.top().object;
    }

    void pop()
    {
        queue_.pop();
        if (queue_.empty())
            counter_ = 0;
    }

    std::priority_queue<Proxy, std::vector<Proxy>, ProxyComp> queue_;
    counter_type                                              counter_ = 0;
};

struct lower_priority
{
    bool operator ()(const Lettura& l, const Lettura& r) const
    {
        return l.priorita < r.priorita;
    }
};

int main()
{
    stable_priority_queue<Lettura, lower_priority> coda;

    Lettura l1(50, 'a', standard);
    Lettura l2(50, 'b', standard);
    Lettura l3(120, 'c', standard);
    Lettura l4(100, 'd', standard);
    Lettura l5(30, 'e', urgent);
    Lettura l6(35, 'f', standard);

    coda.push(l1);
    coda.push(l2);
    coda.push(l3);
    coda.push(l4);
    coda.push(l5);
    coda.push(l6);


    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
}

下面是另一种可能的稳定的优先级队列实现,它保持优先级队列提供的相同接口:

template <class T>
struct stable_element
{
    stable_element(T&& o, std::size_t c)
        : object_(std::move(o))
        , insertion_order_(c)
    {
    }
    stable_element(const T& o, std::size_t c)
        : object_(o)
        , insertion_order_(c)
    {
    }
    operator T() { return object_; }

    T object_;
    std::size_t insertion_order_;
};

template <class T>
bool operator<(const stable_element<T>& lhs, const stable_element<T>& rhs)
{
    return (lhs.object_ < rhs.object_) || (!(rhs.object_ < lhs.object_) && (rhs.insertion_order_ < lhs.insertion_order_));
}

template <class T,
          class Container = std::vector<stable_element<T>>,
          class Compare = std::less<typename Container::value_type>>
class stable_priority_queue : public std::priority_queue<stable_element<T>, Container, Compare>
{
    using stableT = stable_element<T>;
    using std::priority_queue<stableT, Container, Compare>::priority_queue;
public:
    const T& top() { return this->c.front().object_; }
    void push(const T& value) {
        this->c.push_back(stableT(value, counter_++));
        std::push_heap(this->c.begin(), this->c.end(), this->comp);
    }
    void push(T&& value) {
        this->c.push_back(stableT(std::move(value), counter_++));
        std::push_heap(this->c.begin(), this->c.end(), this->comp);
    }
    template<class ... Args>
    void emplace(Args&&... args) {
        this->c.emplace_back(T(std::forward<Args>(args)...), counter_++);
        std::push_heap(this->c.begin(), this->c.end(), this->comp);
    }
    void pop() {
        std::pop_heap(this->c.begin(), this->c.end(), this->comp);
        this->c.pop_back();
        if (this->empty()) counter_ = 0;
    }

protected:
    std::size_t counter_ = 0;
};
输出:

top: { valore: 30, sensore: e, priorita: urgent }
top: { valore: 50, sensore: a, priorita: standard }
top: { valore: 50, sensore: b, priorita: standard }
top: { valore: 120, sensore: c, priorita: standard }
top: { valore: 100, sensore: d, priorita: standard }
top: { valore: 35, sensore: f, priorita: standard }

这里是所有这些组合的一个演示

您显示的是值11、12、13、14、15,但推送的是值50、50、100等等。您使用的是什么值?这些值不是11、12…而是l1、l2、l3…带有“L”而不是“1”。从该链接看不出它是编译器错误还是标准错误-这只是您对它应该如何运行的看法rk,我不想在这里讨论。在这两种情况下,它对OP都没有帮助。@latedeveloper这意味着只有一件事你不知道有堆的算法。很多关于算法的书中都描述了它们。请在阅读之前阅读它们,对书中的算法说些什么,书中描述了如何选择元素。你能补充一下吗有什么解释吗?@ConfusedByCode我扩展了我的答案。希望这现在更清楚了
#include <iostream>
#include <string>
#include <queue>
#include <algorithm>


enum Priority
{
    zero, standard, urgent
};

inline std::ostream& operator <<(std::ostream& os, const Priority& p)
{
    switch (p) {
        case zero:
            return os << "zero";
        case standard:
            return os << "standard";
        case urgent:
            return os << "urgent";
    }
}

class Lettura
{
public:
    int      valore;
    char     sensore;
    Priority priorita;

    Lettura()
        : valore(0)
        , sensore('\0')
        , priorita(zero) {}

    Lettura(const int val, const char s = '\0', const Priority p = zero)
        : valore(val)
        , sensore(s)
        , priorita(p) {}

    friend std::ostream& operator <<(std::ostream& out, const Lettura& lett)
    {
        return out << "{ valore: " << lett.valore << ", sensore: " << lett.sensore << ", priorita: " << lett.priorita
                   << " }";
    }
};


template<class T, class Comp>
struct stable_priority_queue
{
    using counter_type = std::size_t;

    struct Proxy
    {
        Proxy(T&& o, counter_type c)
            : object(std::move(o))
            , insertion_order_(c) {}

        Proxy(const T& o, counter_type c)
            : object(o)
            , insertion_order_(c) {}

        T            object;
        counter_type insertion_order_;
    };

    struct ProxyComp
    {
        bool operator ()(Proxy const& l, Proxy const& r) const
        {
            if (major_order_(l.object, r.object))
                return true;
            if (major_order_(r.object, l.object))
                return false;
            return minor_order_(l.insertion_order_, r.insertion_order_);
        }

        Comp           major_order_;
        std::greater<> minor_order_;
    };


    decltype(auto) push(T item)
    {
        return queue_.emplace(std::move(item), counter_++);
    }

    T const& top() const
    {
        return queue_.top().object;
    }

    void pop()
    {
        queue_.pop();
        if (queue_.empty())
            counter_ = 0;
    }

    std::priority_queue<Proxy, std::vector<Proxy>, ProxyComp> queue_;
    counter_type                                              counter_ = 0;
};

struct lower_priority
{
    bool operator ()(const Lettura& l, const Lettura& r) const
    {
        return l.priorita < r.priorita;
    }
};

int main()
{
    stable_priority_queue<Lettura, lower_priority> coda;

    Lettura l1(50, 'a', standard);
    Lettura l2(50, 'b', standard);
    Lettura l3(120, 'c', standard);
    Lettura l4(100, 'd', standard);
    Lettura l5(30, 'e', urgent);
    Lettura l6(35, 'f', standard);

    coda.push(l1);
    coda.push(l2);
    coda.push(l3);
    coda.push(l4);
    coda.push(l5);
    coda.push(l6);


    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
    std::cout << "top: " << coda.top() << "\n";
    coda.pop();
}
top: { valore: 30, sensore: e, priorita: urgent }
top: { valore: 50, sensore: a, priorita: standard }
top: { valore: 50, sensore: b, priorita: standard }
top: { valore: 120, sensore: c, priorita: standard }
top: { valore: 100, sensore: d, priorita: standard }
top: { valore: 35, sensore: f, priorita: standard }
template <class T>
struct stable_element
{
    stable_element(T&& o, std::size_t c)
        : object_(std::move(o))
        , insertion_order_(c)
    {
    }
    stable_element(const T& o, std::size_t c)
        : object_(o)
        , insertion_order_(c)
    {
    }
    operator T() { return object_; }

    T object_;
    std::size_t insertion_order_;
};

template <class T>
bool operator<(const stable_element<T>& lhs, const stable_element<T>& rhs)
{
    return (lhs.object_ < rhs.object_) || (!(rhs.object_ < lhs.object_) && (rhs.insertion_order_ < lhs.insertion_order_));
}

template <class T,
          class Container = std::vector<stable_element<T>>,
          class Compare = std::less<typename Container::value_type>>
class stable_priority_queue : public std::priority_queue<stable_element<T>, Container, Compare>
{
    using stableT = stable_element<T>;
    using std::priority_queue<stableT, Container, Compare>::priority_queue;
public:
    const T& top() { return this->c.front().object_; }
    void push(const T& value) {
        this->c.push_back(stableT(value, counter_++));
        std::push_heap(this->c.begin(), this->c.end(), this->comp);
    }
    void push(T&& value) {
        this->c.push_back(stableT(std::move(value), counter_++));
        std::push_heap(this->c.begin(), this->c.end(), this->comp);
    }
    template<class ... Args>
    void emplace(Args&&... args) {
        this->c.emplace_back(T(std::forward<Args>(args)...), counter_++);
        std::push_heap(this->c.begin(), this->c.end(), this->comp);
    }
    void pop() {
        std::pop_heap(this->c.begin(), this->c.end(), this->comp);
        this->c.pop_back();
        if (this->empty()) counter_ = 0;
    }

protected:
    std::size_t counter_ = 0;
};
enum Priority
{
    zero, standard, urgent
};

inline std::ostream& operator <<(std::ostream& os, const Priority& p)
{
    switch (p) {
        case zero:
            os << "zero"; break;
        case standard:
            os << "standard"; break;
        case urgent:
            os << "urgent"; break;
    }
    return os;
}

class Lettura
{
public:
    int      valore;
    char     sensore;
    Priority priorita;

    Lettura()
        : valore(0)
        , sensore('\0')
        , priorita(zero) {}

    Lettura(const int val, const char s = '\0', const Priority p = zero)
        : valore(val)
        , sensore(s)
        , priorita(p) {}

    friend std::ostream& operator <<(std::ostream& out, const Lettura& lett)
    {
        return out << "{ valore: " << lett.valore << ", sensore: " << lett.sensore << ", priorita: " << lett.priorita
                   << " }";
    }
};

bool operator<(const Lettura& l, const Lettura& r)
{
    return l.priorita < r.priorita;
}

int main()
{
    stable_priority_queue<Lettura> coda;

    Lettura l1(50, 'a', standard);
    Lettura l2(50, 'b', standard);
    Lettura l3(120, 'c', standard);
    Lettura l5(30, 'e', urgent);
    Lettura l6(35, 'f', standard);

    coda.push(l1);
    coda.push(l2);
    coda.push(l3);
    coda.emplace(100, 'd', standard);
    coda.emplace(l5);
    coda.emplace(l6);

    while (!coda.empty()) {
        std::cout << "top: " << coda.top() << "\n";
        coda.pop();
    }
}
top: { valore: 30, sensore: e, priorita: urgent }
top: { valore: 50, sensore: a, priorita: standard }
top: { valore: 50, sensore: b, priorita: standard }
top: { valore: 120, sensore: c, priorita: standard }
top: { valore: 100, sensore: d, priorita: standard }
top: { valore: 35, sensore: f, priorita: standard }