如何合并两个priority_queue?

时间:2013-04-06 14:55:16

标签: c++ c++11

我有priority_queue两个float,如下所示:

std::priority_queue<float> queue1;
std::priority_queue<float> queue2;

我需要合并它们。但STL merge算法不允许直接使用priority_queue

merge(
  queue1.begin(), queue2.end(),
  queue2.begin(), queue2.end(),
  queue1
);

有没有办法在不使用辅助数据结构的情况下合并priority_queue

3 个答案:

答案 0 :(得分:4)

priority_queue是容器适配器,而不是常规标准容器。特别是,它不提供begin()end()成员函数。因此,您必须从一个队列中弹出元素并将它们推送到另一个队列中:

while (!queue2.empty())
{
    queue1.push(queue2.top());
    queue2.pop();
}

答案 1 :(得分:3)

除了安迪的答案外,一项重要的优化工作是始终将优先级较小的队列中的元素合并到优先级较大的队列中。可以使用std::swap

// merge elements into dest from src
template<typename T>
void merge_pq(std::priority_queue<T>& dest, std::priority_queue<T>& src) {
  if (dest.size() < src.size()) {
    std::swap(dest, src);
  }
  while (!src.empty()) {
    dest.push(src.top());
    src.pop();
  }
}

这可以带来真正的改变,尤其是当两个优先级队列的大小完全不同时。

在最近的Facebook Hacker Cup编程竞赛中,有一个问题要求您将优先级队列合并为更大算法的一部分。如果您没有进行此优化,那么您的代码将花费很长时间,并且您不会得到正确的问题。这发生在我身上;在没有进行此优化的情况下,我的代码花了5分钟才能运行,但是在比赛结束后我添加了此优化,不到10秒。我没有得到这个问题的荣誉。希望如果您正在阅读本文,并且遇到类似的问题,您将会更加成功:)

答案 2 :(得分:1)

您可以从队列中"steal" underlying containers,合并它们并从合并的容器中构造另一个priority_queue,而不是像以前建议的那样逐个处理它们:

// https://stackoverflow.com/a/1385520/8414561
template <class T, class S, class C>
S& Container(std::priority_queue<T, S, C>& q) {
    struct HackedQueue : private std::priority_queue<T, S, C> {
        static S& Container(std::priority_queue<T, S, C>& q) {
            return q.*&HackedQueue::c;
        }
    };
    return HackedQueue::Container(q);
}

int main()
{
    std::priority_queue<int> queue1{std::less<int>{}, {1,2,3,4,5,6,7}};
    std::priority_queue<int> queue2{std::less<int>{}, {10,14,15}};

    auto v1 = std::move(Container(queue1));
    auto v2 = std::move(Container(queue2));

    v1.insert(v1.end(), std::make_move_iterator(v2.begin()), std::make_move_iterator(v2.end()));

    std::priority_queue<int>queue3{std::less<int>{}, std::move(v1)};
    while (!queue3.empty()) {
        std::cout << queue3.top() << std::endl;
        queue3.pop();
    }
}

Live example