在进行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
答案 0 :(得分:5)
我猜他们为什么这样做是因为他们不想使用您在解决方案中使用的array.pop
和array.push
。
这是一个教程,你正在学习实现一个STACK,所以如果你使用ruby数组(pop
和push
)给出的内置方法,那那就没用了:)。
所以基本上他们试图让你的东西不那么抽象,所以你需要忘记ruby已经包含pop
和push
然后编写一个解决方案,它看起来就像他们的解决方案之后这一点。
我并不是要批评你,只是说这是什么意思。
记得在大学时我们把所有时间花在实现堆栈和套接字和东西上,后来我们意识到,对于非常东西,他们是一个扩展定义。所以我建议忘掉你所知道的一切,然后做这些练习:)。
答案 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
被推入堆栈。这可能是你的代码未通过测试的原因。)