STL优先级队列-删除一个项目

发布于 2024-09-05 23:23:42 字数 234 浏览 2 评论 0原文

我想使用 C++ STL priority_queue 容器适配器实现计时器排队系统。

我的问题是我想偶尔取消计时器,但是没有接口可以让我轻松删除priority_queue中不是顶部项目的项目。

有什么建议吗?

感谢您的帮助。

I want to implement a timer queuing system using the C++ STL priority_queue container adapter.

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.

Any suggestions?.

Thank you for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

雨后彩虹 2024-09-12 23:23:42

我曾经遇到过完全相同的场景,并执行了以下操作:

  • 我保存在 std::priority_queue 中的结构仅包含排序依据的时间和 std::vector的索引。 (在我的例子中,Handlerboost::function,但也可以是指向接口或函数的指针)
  • 添加计时器时,我会找到一个释放 handlers1 向量中的索引并将处理程序存储在该索引处。将索引和时间存储在priority_queue中。将索引作为取消令牌返回给客户端
  • 以取消计时器,传递添加时收到的索引。 清除该索引处的处理程序(对于 boost::function 调用 clear(),如果使用指针,请将其设置为零),
  • 当需要回调计时器时, 获取其优先级队列中的处理程序索引并检查处理程序向量 - 如果该位置的处理程序为空()/NULL,则计时器已被取消。将该处理程序索引标记为空闲2

1 为了快速找到免费索引,我使用了单独的 std::stack 索引。当添加定时器且堆栈为空时,添加到向量末尾;否则弹出顶部索引并使用它。

2 这是将索引推送到空闲索引堆栈时的要点。

整个事情有点棘手且容易出错,特别是当您的计时器回调需要添加或取消计时器时。 这是上面描述的我的取消计时器类的链接,此代码是公共域

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)
  • when adding a timer, I'd find a free index in the vector of handlers1 and store the handler at that index. Store the index and the time in the 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)
  • 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. Mark that handler index as free2.

1 To make finding a free index fast, I used a separate std::stack of indices. 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

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

饭团 2024-09-12 23:23:42

恐怕 STL priority_queue 不提供这样的功能。您可以编写自己的堆类(这并不难)。您甚至可以通过如下肮脏的技巧来使用 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);
}

这将使您删除 O(log n) 。

I'm afraid STL priority_queue doesn't offer such functionality. 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:

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.

变身佩奇 2024-09-12 23:23:42

尽管其他一些答案是这么说的,但可以访问任何标准容器适配器的底层容器,包括 priority_queue,因为容器是作为名为 c 的受保护成员公开的。您可以继承 priority_queue 并扩展接口,或者使用肮脏的技巧,例如 可临时获得对普通priority_queue的访问权限。

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. 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.

策马西风 2024-09-12 23:23:42

我的问题是,我偶尔想取消计时器,但是没有接口可以让我轻松删除priority_queue中不是顶部项目的项目。

如果取消计时器经常发生,那么您需要使用一些不同的结构。 std::map 也没有那么糟糕,尽管 delete_min 的成本会上升。

如果取消计时器的情况很少发生,那么将元素标记为已删除(并在 ::pop 期间忽略它)可能会成功。

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.

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.

If canceling a timer happens rarely, then marking the element as deleted (and ignoring it during ::pop) might do the trick.

谁的新欢旧爱 2024-09-12 23:23:42

STL Priority_queue 容器是专门设计的,因此只有顶部项目可以访问,因此如果您需要能够删除非顶部项目,则必须找到不同的类来使用。

The STL priority_queue container is specifically designed so that only the top item is accessible, so if you need to be able to remove non-top items, you're going to have to find a different class to use.

通知家属抬走 2024-09-12 23:23:42

我有同样的要求。如果您可以自由更改容器,则可以解决此问题的一个是 std:: set(不允许重复)或std::multiset

两者都是有序的,并且可以擦除容器大小对数的元素(详细信息请参阅文档)。
如需在多集中删除的帮助,您可能需要查看 这个

在做出决定之前,请先了解 std::set 与 std::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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文