[英]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_heap
、 std::push_heap
和std::pop_heap
来实现的。 这些操作并不稳定,因此您无法保证元素将保持输入的顺序。
如果您需要它们保持输入的顺序,那么您可以做的一件事是编写自己的 object,在向其中添加元素时在底层容器上使用std::stable_sort
。
std::multiset
或std::multimap
只需使用std::multiset
或std::multimap
(从您的情况来看, multimap
看起来是正确的选择)。
https://en.cppreference.com/w/cpp/container/multimap
两者都是订书钉,不会更改插入顺序(自c++11起)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.