【问题标题】:Order of elements with the same priority in std::priority_queuestd::priority_queue 中具有相同优先级的元素的顺序
【发布时间】:2019-10-02 12:43:43
【问题描述】:

我有以下代码:

#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 的规范中没有任何内容说明具有相同优先级的元素是如何排序的。您必须添加有关数据的信息并定义新的排序以考虑插入顺序。
  • 如果您希望具有相同优先级的新元素具有较低的优先级,它们的优先级并不相同,是吗?

标签: c++ stl queue priority-queue


【解决方案1】:

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

按照满足堆属性的顺序。对于相等的元素,哪个是 any 顺序。

对我来说重要的是,如果有任何新元素进入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++}));

【讨论】:

    【解决方案2】:

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

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

    写出正确的某事的最简单方法可能是使用map&lt;key, list&lt;val&gt;&gt;,尽管如果您需要它更快,这可能并不理想。手动stable_sort 容器的建议算法复杂度更差,但在大多数实际情况下可能表现更好。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        使用std::multisetstd::multimap

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

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

        两者都是主食并且不会改变插入顺序(因为)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-03-15
          • 1970-01-01
          • 1970-01-01
          • 2011-10-18
          • 2021-11-29
          • 2022-01-16
          • 2012-04-21
          • 1970-01-01
          相关资源
          最近更新 更多