繁体   English   中英

std::priority_queue 中具有相同优先级的元素的顺序

[英]Order of elements with the same priority in std::priority_queue

我有以下代码:

#include <iostream>
#include <map>
#include <list>
#include <queue>
#include <memory>

enum class CommandType : uint8_t {
  Comm1,
  Comm2, 
  Comm3, 
  Comm4, 
  Comm5 
};

enum class Priority {
  HIGH,
  MEDIUM, 
  LOW
};

std::map<CommandType, Priority> priorities = {
    { CommandType::Comm1, Priority::LOW }, 
    { CommandType::Comm2, Priority::LOW }, 
    { CommandType::Comm3, Priority::LOW }, 
    { CommandType::Comm4, Priority::LOW }, 
    { CommandType::Comm5, Priority::LOW }
};

class QueueEntry 
{
 public:
    QueueEntry(CommandType type)
        : type_(type) {}
    CommandType getType() { return type_; }

private:
  CommandType type_;
};

struct QueueEntryPriorityComparator  {
    bool operator()(std::unique_ptr<QueueEntry>& entry1, std::unique_ptr<QueueEntry>& entry2) const
    {
        auto p1 = priorities.at(entry1->getType());
        auto p2 = priorities.at(entry2->getType());

        return p1 < p2;
    }
};

std::priority_queue<std::unique_ptr<QueueEntry>, std::deque<std::unique_ptr<QueueEntry>>, QueueEntryPriorityComparator> q;

void print()
{
    decltype(q) queueCopy;
    queueCopy.swap(q);

    while (!queueCopy.empty()) {
        auto& top = queueCopy.top();

        std::cout << "Command type: " << static_cast<uint32_t>(top->getType()) << std::endl;;

        q.emplace(std::make_unique<QueueEntry>(top->getType()));

        queueCopy.pop();
    }
}

int main()
{


    q.emplace(std::make_unique<QueueEntry>(CommandType::Comm1));
    q.emplace(std::make_unique<QueueEntry>(CommandType::Comm2));
    q.emplace(std::make_unique<QueueEntry>(CommandType::Comm3));
    q.emplace(std::make_unique<QueueEntry>(CommandType::Comm4));
    q.emplace(std::make_unique<QueueEntry>(CommandType::Comm5));

    print();

    std::cout << std::endl;

    print();

    std::cout << std::endl;

    print();



    return 0;
}

每个元素都有相同的优先级,即Priority::LOW

问题是,这些元素如何放置在priority_queue中?

每当我打印队列时,元素都在不同的位置。 对我来说重要的是,如果有任何新元素进入priority_queue,则应将其放在具有相同优先级的最后一个元素之后。

可以通过使用std::priority_queue来实现还是我必须自己包装它?

问题是,这些元素是如何放在priority_queue 中的?

以满足堆属性的顺序。 对于相等的元素,这是任何顺序。

对我来说重要的是,如果有任何新元素进入priority_queue,则应将其放在具有相同优先级的最后一个元素之后。

您可以通过将订单作为优先级的一部分来实现这一点。 但是要使其成为优先级的一部分,您需要首先使 order 成为元素的一部分。 您可以使用正在运行的计数器:

struct OrderedQueueEntry {
    QueueEntry entry;
    int index;
};

struct OrderedQueueEntryPriorityComparator  {
    bool operator()(std::unique_ptr<OrderedQueueEntry>& left, std::unique_ptr<OrderedQueueEntry>& right) const
    {
        auto pl = priorities.at(left->entry.getType());
        auto pr = priorities.at(right->entry.getType());

        return pl == pr
            ? left->index < right->index;
            : pl < pr;
    }
};

int i = 0;
q.emplace(std::make_unique<OrderedQueueEntry>({CommandType::Comm1, i++}));
q.emplace(std::make_unique<OrderedQueueEntry>({CommandType::Comm2, i++}));
q.emplace(std::make_unique<OrderedQueueEntry>({CommandType::Comm3, i++}));
q.emplace(std::make_unique<OrderedQueueEntry>({CommandType::Comm4, i++}));
q.emplace(std::make_unique<OrderedQueueEntry>({CommandType::Comm5, i++}));

如果您想要一个保证相等比较元素保留插入顺序的优先级队列,您需要自己编写它。

当然std::priority_queue不保证这种插入顺序(如果它被实现为堆,那也不保证它)。

编写正确内容的最简单方法可能是使用map<key, list<val>> ,尽管如果您需要它快速,这可能并不理想。 手动对容器进行stable_sort的建议算法复杂性更差,但尽管如此,在大多数实际情况下可能表现更好。

std::priority_queue是通过在底层容器上使用std::make_heapstd::push_heapstd::pop_heap来实现的。 这些操作并不稳定,因此您无法保证元素将保持输入的顺序。

如果您需要它们保持输入的顺序,那么您可以做的一件事是编写自己的 object,在向其中添加元素时在底层容器上使用std::stable_sort

使用std::multisetstd::multimap

只需使用std::multisetstd::multimap (从您的情况来看, multimap看起来是正确的选择)。

https://en.cppreference.com/w/cpp/container/multimap

两者都是订书钉,不会更改插入顺序(自起)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM