实现给定堆栈的最有效方法

时间:2011-08-20 06:33:02

标签: performance stack

我有一个Stack规范,其中---> *可以查看具有最高(或最低)值的对象。 *堆栈中的每个对象都是可比较的。

我希望尽快实施以下操作

  1. void push(E e);

  2. void pop(E e);

  3. E peekMidElement(); [大小()/ 2)+1]

  4. E peekHighestElement();

  5. E peekLowestElement();

  6. int size();

  7. 效率必须成为中心。推荐的方式是什么?欢迎提出想法。

    编辑:所有要经常调用的方法。此外,重要的是时间效率。

4 个答案:

答案 0 :(得分:1)

其中一种方法是使用数组实现堆栈。然而,这确实限制了堆栈中可以存在的元素的数量(即,阵列的最大尺寸是有限的)。你也可能需要为数组分配空间(你可以做一些realloc魔法来重新增加数组的大小,如果它增长更多)

数组实现的优点是......你必须跟踪一个将成为堆栈顶部的变量。窥视中间只是数组的索引。

希望这有帮助

推送:顶部变量将索引指向顶部元素所在的数组...当执行推送时......只需将值存储在顶部之后的下一个元素处(当然,在进行限制检查后)...和然后你可以增加顶部的值

Pop:递减顶部...返回(顶部+ 1)

的值

PeekMiddle:它总是数组[top / 2]

PeekHighest:它总是数组[顶部]

PeekMiddle:它总是数组[0]

尺寸:返回顶部

以上所有操作均为O(1)

答案 1 :(得分:0)

“效率”太笼统,特别是面对6种方法? CPU效率?内存占用?每个函数被称为相同的次数吗?平均堆栈有多大?

在总摘要中,我会说单个链接列表是个好主意,假设(似乎有道理)sizepeekMidElement通常不会被调用。

答案 2 :(得分:0)

如果您知道堆栈大小的上限,则使用数组(如另一个答案中所述)可能是合理的事情。所有六个操作都是O(1),如果堆栈经常接近其最大大小,则每个元素的存储是最佳的。

另一方面,如果您不知道堆栈大小的上限,或者堆栈大小通常与上限相比较小,则使用双向链表,如下所述。同样,所有六个操作都是O(1)。如果堆栈操作接近最小尺寸,则每个元素的存储是最佳的 - 您将不会有大量未使用的阵列空间。注意,下面显示为“new”和“free”的内存分配可以包含malloc()和free()调用,也可以是通过使用可用节点池来限制开销的一些常用方法。

让H指向列表的头部,T指向尾部,M指向中间。 (M可以在每次更改时保持时间O(1),如下所示。)初始化列表大小s = 0和mid-count m = 0。

对于您的操作1-6:

  1. void push(E e):
    使用值e创建新节点X; ++ S; if(s == 1)设置H = T = M = X并设置链接,否则{在X处附加X;设H = X;如果m<(s / 2 + 1)则{++ m并设置M = M.next}}。

  2. void pop(E e):如果s< 1则返回null或错误; else {get value e = He返回,设置H = H.next,unlink和free H.prev, - s,if(s == 0)H = T = M = null否则如果m>(s / 2) +1)然后{--m并设置M = M.prev}}。

  3. E peekMidElement(); [size()/ 2)+1]:如果是M,则返回M.e else null

  4. E peekHighestElement():如果是H,则返回H.e(或T.e?),否则为null

  5. E peekLowestElement():如果为T,则返回T.e(或H.e?),否则为null

  6. int size():返回s

  7. 我不知道堆栈的哪一端是“高”;你认为它在成长或成长吗?无论如何,只需修复操作4& 5,如你所愿,并更改为peekHeadElement或peekFirstElement等名称。

答案 3 :(得分:0)

在这种情况下,数组实现是理想的,但我不确定您的描述是否仍然可以称为堆栈。实施时需要注意的一些要点如下:

  1. 按下数组的右侧。如果超出阵列容量,则可以分配新阵列,复制所有元素并删除以前的分配。所有这些都是由大多数语言中的一些基于数组的容器类自动处理的。但是,有一些方法可以避免大部分复制,同时扩展堆栈的容量,这可能会导致某些其他操作的效率降低。

  2. 如果你保留一个索引来标记下一个插入(即push(E e)),pop()可以像" - ;"那样简单实现。

  3. peekMiddle()只是(size / 2)索引上的元素。我希望你不是要寻找中值。

  4. 对于peekLowest(),简单的解决方案是保持一堆最小值,即当你将一个值推入堆栈时,如果它是新的最小值,也将它推到最小堆栈上。这样,最小堆栈的最高值将是peekLowest()的答案。当然,当你从原始堆栈中弹出一个值时,如果它是最小值(由peekLowest()给出),也会从最小堆栈中弹出它。类似的方法可以用于peekHighest()。

  5. 通过这个简单的实现,您应该能够为所有操作获得O(1)运行时间。对于推(E e),O(1)是摊销的运行时间。