如何从priority_queue中删除不在顶部的元素?

ish*_*243 29 c++ stl priority-queue binary-heap

在我的程序中,我需要从不在顶部的优先级队列中删除一个元素.可以这样做吗?如果没有,请建议一种方法,除了创建自己的堆.

ale*_*exm 28

标准priority_queue<T>可以通过继承来定制.它保护的成员c,并comp可以在子类中被引用.

template<typename T>
class custom_priority_queue : public std::priority_queue<T, std::vector<T>>
{
  public:

      bool remove(const T& value) {
        auto it = std::find(this->c.begin(), this->c.end(), value);
        if (it != this->c.end()) {
            this->c.erase(it);
            std::make_heap(this->c.begin(), this->c.end(), this->comp);
            return true;
       }
       else {
        return false;
       }
 }
};

void main()
{
   custom_priority_queue<int> queue;

   queue.push(10);
   queue.push(2);
   queue.push(4);
   queue.push(6);
   queue.push(3);

   queue.remove(6);

   while (!queue.empty())
   {
      std::cout << queue.top();
      queue.pop();

      if (!queue.empty())
      {
        std::cout << ", ";
      }
   }

 }
Run Code Online (Sandbox Code Playgroud)

输出:

10,4,3,2

  • @klaustriendl,你能解释为什么`make_heap` 是不必要的,特别是如果被移除的项目碰巧在顶部/多个项目被移除?我的猜测是,只有当堆完全排序时才不需要 `make_heap`,但事实并非如此。 (6认同)
  • 不需要调用“make_heap”,因为堆仍然是有序的。 (3认同)
  • @Aelian 你说得对,感谢你发现我的错误。似乎我误解了堆的属性,所以我将“排序”误认为“结构化”。因此,如果您删除一个元素,则需要重新构造堆。 (3认同)
  • @SandeepTuniki:如果你想传递一个自定义的比较器,类声明可以是这样的:`template&lt;typename T, class Container=std::vector&lt;T&gt;, class Compare=std::less&lt;typename Container::value_type &gt;&gt; class custom_priority_queue : public std::priority_queue&lt;T, Container, Compare&gt;` (2认同)

Ami*_*mar 21

最好的解决方案是使用 std::set。Sets 提供了允许它同时用作最小/最大堆(或优先级队列)的方法。

std::set<int> pq;

//accessing the smallest element(use as min heap)
*pq.begin();

//accessing the largest element (use as max heap)
*pq.rbegin();
Run Code Online (Sandbox Code Playgroud)

此外,集合还允许随机删除。

//to delete the integer '6'
auto it = pq.find(6);
pq.erase(it);
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个想法很酷,您可以使用多重集来重复元素。但请记住,当您按值而不是迭代器进行擦除时要注意。 (6认同)
  • 如果元素可以重复,则此解决方案将不起作用。 (5认同)
  • 对于重复的元素,您可以简单地使用地图。只需保留钥匙的数量,当钥匙的数量变为 0 时,删除钥匙。使用相同的想法解决了这个问题https://www.spoj.com/problems/ARRAYSUB/ (4认同)

Ris*_*ain 8

处理priority_queue STL 删除的一个巧妙的小技巧——使用另一个priority_queue,例如,del_pq。继续插入所有删除值。当您从原始优先级队列中弹出值时,请检查 top ofdel_pq并查看我们是否要删除它。如果匹配,则从原始 priority_queue 中删除该值。

这个方法实现了一种懒惰地删除我们原始优先级队列中的值的方法。可以占用两倍的内存,但平均删除和插入保持不变O(logN)


小智 5

Pradip 和 MASh 牺牲了时间来实现删除操作。但是如果时间复杂度对你很重要,我建议你使用 hash min_heap。哈希表存储值指针,指针指向 min_heap。这意味着您可以花费 O(1) 时间来查找 min_heap 和 O(log(n)) 中的值以删除(向上或向下筛选)元素。

  • 永远不要牺牲时间。 (2认同)

MAS*_*ASh -4

请注意 ,以下方法可以完成任务,但不是解决问题的优化方法。对于优化方法,请检查其他答案。

让你想要删除 中的第 5 个元素priority_queue<type> Q。然后你可以这样做:

vector<type> tempQ;
int i = 0;
int n = 5;
type t;

// backup n-1 items
while(i < n-1)
{
    tempQ.push_back(Q.top());
    Q.pop();        
    i++;
}

// remove the nth item
Q.pop();

// restore the backed up items
i = 0;
while(i < n-1)
{
    t = tempQ[i++];
    Q.push(t);
}
Run Code Online (Sandbox Code Playgroud)