简体   繁体   English

STL优先级队列 - 删除项目

[英]STL Priority Queue - deleting an item

I want to implement a timer queuing system using the C++ STL priority_queue container adapter. 我想使用C ++ STL priority_queue容器适配器实现计时器排队系统。

My problem is that I want to occasionally cancel a timer, however there are no interfaces that enable me to easily delete an item in the priority_queue that is not the top item. 我的问题是我偶尔会取消一个计时器,但是没有接口可以让我轻松删除priority_queue中不是顶级项目的项目。

Any suggestions?. 有什么建议么?。

Thank you for your help. 谢谢您的帮助。

I had the exact same scenario once and did the following: 我有一个完全相同的场景,并做了以下事情:

  • the structure I kept in std::priority_queue contained only the time to sort by and an index to a std::vector<Handler> (in my case Handler was boost::function , but could as well be pointer to interface or function) 我在std::priority_queue中保存的结构只包含排序时间和std::vector<Handler>的索引(在我的情况下, Handlerboost::function ,但也可以是指向接口或函数的指针)
  • when adding a timer, I'd find a free index in the vector of handlers 1 and store the handler at that index. 添加计时器时,我会在处理程序1的向量中找到一个自由索引,并将处理程序存储在该索引处。 Store the index and the time in the priority_queue. 将索引和时间存储在priority_queue中。 Return the index to the client as token to cancel 将索引作为标记返回给客户端以取消
  • to cancel a timer, pass the index received when adding it. 取消定时器,传递添加时收到的索引。 Clear the handler at that index (for boost::function call clear() , if using pointers, set it to zero) 清除该索引处的处理程序(对于boost::function调用clear() ,如果使用指针,则将其设置为零)
  • when it's time to callback a timer, get its handler index from the priority queue and check the handlers vector - if the handler at that position is empty()/NULL, the timer has been canceled. 当回调计时器时,从优先级队列中获取其处理程序索引并检查处理程序向量 - 如果该位置的处理程序为空()/ NULL,则计时器已被取消。 Mark that handler index as free 2 . 将处理程序索引标记为free 2

1 To make finding a free index fast, I used a separate std::stack of indices. 1为了快速找到一个自由索引,我使用了一个单独的std::stack索引。 When adding a timer and that stack is empty, add at the end of vector; 添加计时器并且该堆栈为空时,在向量的末尾添加; otherwise pop the top index and use it. 否则弹出顶部索引并使用它。

2 Here's the point when you push the index to the free indices stack 2这是将索引推送到自由索引堆栈时的要点

The whole thing is somewhat tricky and error-prone, especially if your timer callbacks need to add or cancel timers. 整个过程有点棘手且容易出错,特别是如果您的计时器回调需要添加或取消计时器。 Here's a link to my canceling timer class described above, this code is public domain 这是我上面描述的取消计时器类的链接,此代码是公共域

I'm afraid STL priority_queue doesn't offer such functionality. 我担心STL priority_queue不提供这样的功能。 You can write your own heap class (which is not that hard). 您可以编写自己的堆类(这并不难)。 You could even use the std::xxx_heap functions by dirty tricks like this: 你甚至可以通过像这样的脏技巧使用std::xxx_heap函数:

delete_heap(iterator to_delete, iterator heap_begin, iterator heap_end)
{
  to_delete->key = something that would compare less to everything; // make sure it gets to the top in the next step
  std::push_heap(heap_begin, to_delete+1);
  std::pop_heap(heap_begin, heap_end);
}

which will get you O(log n) delete. 这会让你O(log n)删除。

Despite what some other answers say, it is possible to access the underlying container of any standard container adapter, including priority_queue , since the container is exposed as a protected member called c . 尽管其他一些答案说,但是可以访问任何标准容器适配器的底层容器,包括priority_queue ,因为容器是作为受保护的成员c公开的。 You can either inherit from priority_queue and extend the interface, or use dirty tricks such as this to temporarily gain access to a normal priority_queue . 您可以从继承priority_queue和扩展接口,或使用下三滥的手段,如这种暂时获得正常priority_queue

My problem is that I want to occasionally cancel a timer, however there are no interfaces that enable me to easily delete an item in the priority_queue that is not the top item. 我的问题是我偶尔会取消一个计时器,但是没有接口可以让我轻松删除priority_queue中不是顶级项目的项目。

If canceling a timer happens often, then you need to use some different structure. 如果经常取消定时器,那么您需要使用一些不同的结构。 std::map isn't that bad too, though cost of delete_min would go up. 尽管delete_min的成本会上升,但std :: map也不是那么糟糕。

If canceling a timer happens rarely, then marking the element as deleted (and ignoring it during ::pop) might do the trick. 如果很少取消定时器,那么将元素标记为已删除(并在:: pop期间忽略它)可能会起作用。

STL priority_queue容器是专门设计的,因此只能访问顶级项目,因此如果您需要能够删除非顶级项目,则必须找到要使用的其他类。

I had the same requirement. 我有同样的要求。 If you have the freedom to change the container, the one that can solve this problem is std::set (no duplicates allowed) or std::multiset . 如果您可以自由更改容器,则可以解决此问题的是std :: set (不允许重复)或std :: multiset

Both are ordered and can erase an element logarithmic in container size (see the documentation for details). 两者都是有序的,可以删除容器大小的对数元素(有关详细信息,请参阅文档)。 For help in deleting in multi set you might want to see this . 有关在多集中删除的帮助,您可能希望看到这一点

See the difference std::set vs std::priority_queue before deciding. 在决定之前,请查看差异std :: set vs std :: priority_queue

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM