使用nils填充堆栈并将“top”解释为最后的非零值是否有一些优势?

时间:2013-10-26 15:34:23

标签: ruby

在进行rubymonk练习时,我被要求实施一个具有硬大小限制的堆栈。如果我尝试推送太多值,或者我尝试弹出空堆栈,它应该返回'nil'。

我的解决方案如下,然后是他们的解决方案。我通过了我可以在IDE中给出的每个测试,而它没有通过rubymonk的测试。但这不是我的问题。

问题是,为什么他们选择用nils填充堆栈而不是让它像我的版本那样缩小和增长?

它只是使他们的代码更复杂。

这是我的解决方案:

class Stack
  def initialize(size)
    @max = size
    @store = Array.new
  end

  def pop
    empty? ? nil : @store.pop
  end

  def push(element)
    return nil if full?
    @store.push(element)
  end

  def size
    @store.size
  end

  def look
    @store.last
  end

  private

  def full?
    @store.size == @max
  end

  def empty?
    @store.size == 0
  end
end

这是接受的答案

class Stack
  def initialize(size)
    @size = size
    @store = Array.new(@size)
    @top = -1
  end

  def pop
    if empty?
      nil
    else
      popped = @store[@top]
      @store[@top] = nil
      @top = @top.pred
      popped
    end
  end

  def push(element)
    if full? or element.nil?
      nil
    else
      @top = @top.succ
      @store[@top] = element
      self
    end
  end

  def size
    @size
  end

  def look
    @store[@top]
  end

  private

  def full?
    @top == (@size - 1)
  end

  def empty?
    @top == -1
  end
end

3 个答案:

答案 0 :(得分:5)

我猜他们为什么这样做是因为他们不想使用您在解决方案中使用的array.poparray.push。 这是一个教程,你正在学习实现一个STACK,所以如果你使用ruby数组(poppush)给出的内置方法,那那就没用了:)。

所以基本上他们试图让你的东西不那么抽象,所以你需要忘记ruby已经包含poppush然后编写一个解决方案,它看起来就像他们的解决方案之后这一点。

我并不是要批评你,只是说这是什么意思。

记得在大学时我们把所有时间花在实现堆栈和套接字和东西上,后来我们意识到,对于非常东西,他们是一个扩展定义。所以我建议忘掉你所知道的一切,然后做这些练习:)。

答案 1 :(得分:1)

当他们试图找到顶部时,他们的解决方案不会测试nil。

它们使用@top值作为最顶层元素的索引,并在添加或删除新元素时递增和递减它。这是通过@top.succ@top.pred方法调用完成的。

没有特别的原因,为什么他们用nils填充他们的堆栈,当一些东西被弹出。从理论上讲,它们可以减少@top计数器,并保留那个堆栈位置处的任何内容。正如@Jan Dvorak所指出的那样,堆栈再次被nils填充,以防止内存从垃圾收集器中泄漏。

您的版本依赖于Array.pop和Array.push的实现。当弹出一个值时,那些可能实际上并没有缩小分配的空间,尽管我不知道它们的具体实现。

为什么不断更改数组的大小是一个性能问题:

假设您要创建一个大小为2的数组。为此,ruby必须向操作系统询问一块连续未使用且大到足以容纳大小为2的数组的内存。让我们说这需要24字节。

因此,如果您现在想要推送3个值而不是2个,则必须从操作系统请求另一块内存,现在可以保存大小为3的数据的数据。可以说这需要32个字节。这个新位置可能与前一块内存不在同一个位置,因为在前24个字节之后,另一个程序存储了自己的值。现在,您必须将大小为2的数组复制到新位置,然后才能将第3个值添加到该数组中。

现在重点是rubys Array类实际上并不是这样的。它很可能总是请求比你最初从操作系统告诉它更多的内存,并且不会在每次弹出后减少内存。此外,如果它变大,它可能不会增加1个数组元素所要求的内存,但可能只是在内存不足时尝试获得两倍的内存。

答案 2 :(得分:1)

他们没有理由以这种方式实施他们的解决方案。在我看来,作为一个以编写Ruby应用程序为生的人,你的代码更好。

(一个区别是他们不允许nil被推入堆栈。这可能是你的代码未通过测试的原因。)