【问题标题】:Implementing FIFO using LIFO使用 LIFO 实现 FIFO
【发布时间】:2012-03-12 08:08:40
【问题描述】:

在网上看了一些算法练习,发现了一个有趣的:

您将如何使用 LIFO 实现 FIFO?

我自己尝试过,但最终只有一个解决方案:每次我们想要 FIFO 的 front 元素时,将 lifo 复制到另一个 lifo(排除最后一个元素,即最前面),获取最前面的元素并将其移除,然后将第二个 LIFO 复制回第一个 LIFO。

但这当然慢得可怕,它会产生一个像这样的简单循环:

for(!myfifo.empty()) {
  myfifo.pop();
}

在 FIFO 的标准实现上采用 O(n²) 而不是 O(n)

当然,LIFO 不是为了做 FIFO,我们当然不会通过使用“本地”FIFO 和基于 LIFO 的假 FIFO 来获得相同的复杂性,但我认为肯定有一种方法可以做到优于 O(n²)。有人知道吗?

提前致谢。

【问题讨论】:

标签: algorithm fifo


【解决方案1】:

您可以使用 2 个 LIFO [堆栈] 每个 OP FIFO [队列] 获得 amortized time complexityO(1)

假设你有stack1stack2

insert(e):
   stack1.push(e)

take():
   if (stack2.empty()):
      while (stack1.empty() == false):
            stack2.push(stack1.pop())
   return stack2.pop() //assume stack2.pop() handles empty stack already

示例:

push(1)

|1|  | |
|-|  |-|

push(2)
|2|  | |
|1|  | |
|-|  |-|

pop()
push 2 to stack2 and pop it from stack1:
|1|  |2|
|-|  |-|
push 1 to stack2 and pop it from stack2:
| |  |1|
| |  |2|
|-|  |-|
pop1 from stack2 and return it:
| |  |2|
|-|  |-|

要获得真正的O(1) [未摊销],它要复杂得多,需要更多的堆栈,请查看this post 中的一些答案

编辑:复杂性分析:

  1. 每个insert() 都是琐碎的O(1) [只需将其推送到stack1]
  2. 请注意,每个元素最多被push()ed 和pop()ed 两次,一次来自stack1,一次来自stack2。因为没有更多的操作然后这些,对于n元素,我们最多有2npush()s和2npop()s,这给我们最多4n * O(1)复杂性[因为pop()push()O(1)],即O(n) - 我们得到摊销时间:O(1) * 4n / n = O(1)

【讨论】:

  • 是的,这似乎是事实上的答案。我没有想到这样一个事实,直到您将 FIFO 弹出到给定的深度,您才不必担心 FIFO 中发生了什么……非常感谢。我会看一下超过 2 个堆栈的链接。
  • 嗯,在你编辑你的帖子之前我已经明白了,但现在,这是一种皇家的回答,非常感谢!
  • @Undo:不客气,我还添加了一些简短的复杂度分析,以表明这些解决方案确实是O(1)摊销时间复杂度
  • 应该stack1.push(stack2.pop())stack2.push(stack1.pop()) 吗?您想将所有元素从 stack1 获取到 stack2...
【解决方案2】:

LIFO 和 FIFO 都可以用数组来实现,它们之间的唯一区别在于 tailhead 指针的工作方式。假设您从 LIFO 开始,您可以添加两个额外的指针来反映 FIFO 的尾部和头部,然后使用 FIFO 指针向 Add、Remove 等方法添加方法。

输出类型将与专用 FIFO 或 LIFO 类型一样快,但它会同时支持这两种类型。您需要使用独特的类型成员,例如 AddToStack/AddToQueue、RemoveFromStack/RemoveFromQueue 等。

【讨论】:

  • 其实指针并不能解决一切。在这里,我们有一个简单的 LIFO 的想法,比如说一个堆栈。你只有 push() 和 pop() 方法。你既不能访问 LIFO 的内部,也不能使用指针,因为当弹出 FIFO 包装器的前面时,你将如何将所有内容转移到 LIFO 的前面?
  • 此答案假定您可以直接访问该结构并且可以对其进行修改。通过这种方式,您将能够添加额外的指针和额外的方法。您的问题中没有任何内容说不能修改 LIFO 结构。
  • 我明白了。实际上,问题不是“如何将 LIFO 转换为 FIFO”,而是真正的“如何使用 LIFO 实现 fifo”。我似乎不够清楚。但如果我能接触到内在的东西,我基本上只会把 lifo 改成 fifo,当然……!
猜你喜欢
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-28
  • 1970-01-01
相关资源
最近更新 更多