【问题标题】:real life people queue data structure现实生活中的人队列数据结构
【发布时间】:2013-12-09 21:56:18
【问题描述】:

您将如何对现实生活中的人排队进行建模?

考虑到这些主要限制: - 先进先出 - 任何时候随机元素都可以离开队列 - pop 应该总是返回一个仍在队列中的元素 - 队列中的任何元素都是唯一可识别的(例如社会安全号码)

我提出的最佳解决方案是同时维护 fifo 约束的队列和管理离开人员的哈希集。当我在队列中推送一个元素时,我也将它推送到哈希集中。当我从队列中弹出一个元素时,我还会检查散列集。如果元素在弹出之前被删除,我将丢弃它并弹出下一个元素。如果元素仍在散列集中,我会处理该元素,然后将其从散列集中删除。 在这种情况下,push-and-add、pop-and-remove、remove-only 操作在时间上都应该是 O(1) 还是我错了?

我很幸运有一个更有效或更优雅的解决方案

【问题讨论】:

  • 您可能会问自己,移除 O(1) 时间有多重要。如果删除很少发生(对于“现实生活”队列来说是这样),使用具有 O(n) 删除的传统 FIFO 队列可能不会影响程序的整体运行时间。为了简单起见,有很多话要说。

标签: performance algorithm data-structures queue hashset


【解决方案1】:

我在您的解决方案中看到的一个问题是,您似乎永远不会从哈希集中删除元素(除非我遗漏了某些东西),这很糟糕 - 尽管每次操作预计为 O(1),但内存无论有多少人排队,使用量都会不断增加。

我可能已经把它搞砸了:

拥有队列中所有人的哈希映射(队列中的人到迭代器)。

对于入队,您也可以添加到地图中,对于出队,您也可以从地图中删除。

对于删除,由于哈希映射包含迭代器,因此您可以在删除操作的情况下从哈希映射和队列中删除人员。这假设队列被实现为(双)链表,并且仍然是 O(1)。

如果您不熟悉迭代器,它基本上只是指向链表中适用节点的引用或指针。

【讨论】:

  • 对于您在弹出队列时提到的第一个问题,如果元素仍然存在于 O(1) 中,我还可以从哈希集中删除该元素。
  • 如果我使用带有人的哈希图在队列中定位(这是你的意思吗?)我需要在删除一个元素后更新哈希图中的所有后续值 O( n)
  • 你的仍然需要 O(1) 时间,但空间会不断增加。不是位置 - 更像是指向链表中节点的引用或指针 - 因此您不需要在删除后更新任何其他值。
  • 嗯,我认为有参考就可以了。
  • 对于你提到的不断增加的空间,我仍然不明白 hash-set 和 hash-map 之间有什么区别(对不起,如果我错过了一些基本知识,我'数据结构方面的经验很少)
【解决方案2】:

我建议使用一个“普通”队列,其中包含对可以失效的项目的引用。如果尝试获取下一个项目产生一个已被删除的项目,则忽略该项目并继续下一个项目,直到找到未删除的项目或队列为空。这种方法浪费的内存量将受限于进入队列的项目与从前面获取的项目的比率。如果希望避免无限内存浪费的可能性,可以计算添加、无效和删除的项目数,如果队列中的项目数超过例如仍然有效的项目数的五倍加上 1000,锁定队列,将标记加入队列,然后检索并重新加入项目,直到遇到该标记。

【讨论】:

  • 您建议创建一个情侣队列( key ,validity ),但我怎样才能使队列中的随机元素在 O(1) 中无效?
  • @Luky:队列将保存对对象的引用。当一个人被添加到队列中时,给调用者一个对队列持有引用的对象的引用(你可能希望使对象的所有成员,除了一个Invalidate方法,internal这样外代码不能对对象做任何事情,除了使其无效)。或者,您可以保留一个Dictionary,它将 ID 号映射到上述项目,当它们进入队列时将它们添加到字典中,并在它们被提取或失效时将它们删除。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-03
  • 1970-01-01
  • 2020-05-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多