【问题标题】:Updating Priority Queue Order On Element Changes更新元素更改的优先队列顺序
【发布时间】:2019-09-18 11:10:25
【问题描述】:

我发现了一些关于这个主题的类似问题,但我想再次询问以获得更明确的答案。我正在编写一个图匹配算法,其中图上的每个节点根据其邻居的匹配分配给一个优先级集。细节并不重要,但我使用 std::priority_queue 以便首先匹配最高优先级的节点。这里有一个棘手的地方:每次引入新的匹配时,匹配节点的邻居的优先级都要更新。

此算法引用自一篇论文,虽然我实现了完全相同的算法,但我无法达到相同的匹配百分比。我自然怀疑 std::priority_queue 可能不会按照我想要的优先级更新重新排序,所以我运行了一些测试,然后我发现其他问题问同样的事情:

How to tell a std::priority_queue to refresh its ordering?

Does changing a priority queue element result in resorting the queue?

我的问题自然是,如何更新新匹配的订单?我可以强制执行吗?或者是否有任何其他数据结构(例如最大堆)可以用于此目的?请注意,将新元素推入队列对我来说不是一个有效的解决方案。这是我正在使用的代码片段(matchFace() 函数更新元素优先级):

while (priorityQueue.size() != 0) {

    // Take the face at the top of the queue and check if it is already matched
    FaceData* currentFace = priorityQueue.top();

    // Pop the face at the top in any case
    priorityQueue.pop();

    // If the face is not already matched, try to find a matching
    if (!currentFace->matched) {

        // Try to match the face with one of its neighbors, add it to the unmatched faces list if it fails
        int neighborId = matchFace(currentFace);
        if (neighborId == -1) {
            unmatchedFaces.push_back(currentFace);
        } else {
            matchingMap[currentFace->id] = neighborId;
        }
    }
}

【问题讨论】:

  • 能否从队列中移除受影响的元素,更改它们,然后重新添加?
  • 好吧,没关系,使用 std::priority_queue 是不可能的。你可能不得不自己写这个。在这种情况下,priority_queue 可能不是该工作的正确工具。您能解释一下您要解决的更广泛的问题吗?
  • 也许我可以使用节点 ID 进行迭代搜索,但效率非常低。我试图在对偶图上找到最大匹配,其中每个节点都分配给从 0 到 3 的优先级。当节点匹配时,应更新其邻居的优先级,以便具有最高优先级的节点将是首先匹配。这样,空闲邻居数量较少的节点将优先匹配。
  • Boost 的binomial_heap 允许您更新元素并在队列中重新排序。
  • 我最近遇到了类似的问题,我最终做的是从 priority_queue 继承(这里通常是“没有用户可维修的部件”警告)。我在基础集合上添加了一个名为 std::make_heap() 的公共方法(在我的例子中是一个 std::vector )。当其他元素的优先级发生变化时,我调用了这个方法。它不漂亮,但它适用于我的情况。

标签: c++ priority-queue


【解决方案1】:

使用我收到的关于该问题的 cmets,我决定自己回答。我发现有三种可能的方法可以解决这个问题:

  • 实现您自己的可更新优先级队列或使用外部库。为此,Boost 可能有一些额外的数据结构。我还在这里找到了Updatable Priority Queue 源代码。
  • 使用向量存储值,并在每次收到更新时使用算法库中提供的std::make_heap 函数。这是最简单的方法,但运行速度很慢。
  • 删除并重新插入元素。如果这不是一种有效的方法,请使用地图来存储元素 ID,而不是删除元素,而是在地图上标记元素,这样如果您多次遇到它们,您可以忽略它们。另一种策略是通过添加标志来更改项目并通过打开标志来标记元素。

【讨论】:

    猜你喜欢
    • 2018-04-10
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-05
    相关资源
    最近更新 更多