我有一个Stack规范,其中---> *可以查看具有最高(或最低)值的对象。 *堆栈中的每个对象都是可比较的。
我希望尽快实施以下操作
void push(E e);
void pop(E e);
E peekMidElement(); [大小()/ 2)+1]
E peekHighestElement();
E peekLowestElement();
int size();
效率必须成为中心。推荐的方式是什么?欢迎提出想法。
编辑:所有要经常调用的方法。此外,重要的是时间效率。
答案 0 :(得分:1)
其中一种方法是使用数组实现堆栈。然而,这确实限制了堆栈中可以存在的元素的数量(即,阵列的最大尺寸是有限的)。你也可能需要为数组分配空间(你可以做一些realloc魔法来重新增加数组的大小,如果它增长更多)
数组实现的优点是......你必须跟踪一个将成为堆栈顶部的变量。窥视中间只是数组的索引。
希望这有帮助
推送:顶部变量将索引指向顶部元素所在的数组...当执行推送时......只需将值存储在顶部之后的下一个元素处(当然,在进行限制检查后)...和然后你可以增加顶部的值
Pop:递减顶部...返回(顶部+ 1)
的值PeekMiddle:它总是数组[top / 2]
PeekHighest:它总是数组[顶部]
PeekMiddle:它总是数组[0]
尺寸:返回顶部
以上所有操作均为O(1)
答案 1 :(得分:0)
“效率”太笼统,特别是面对6种方法? CPU效率?内存占用?每个函数被称为相同的次数吗?平均堆栈有多大?
在总摘要中,我会说单个链接列表是个好主意,假设(似乎有道理)size
和peekMidElement
通常不会被调用。
答案 2 :(得分:0)
如果您知道堆栈大小的上限,则使用数组(如另一个答案中所述)可能是合理的事情。所有六个操作都是O(1),如果堆栈经常接近其最大大小,则每个元素的存储是最佳的。
另一方面,如果您不知道堆栈大小的上限,或者堆栈大小通常与上限相比较小,则使用双向链表,如下所述。同样,所有六个操作都是O(1)。如果堆栈操作接近最小尺寸,则每个元素的存储是最佳的 - 您将不会有大量未使用的阵列空间。注意,下面显示为“new”和“free”的内存分配可以包含malloc()和free()调用,也可以是通过使用可用节点池来限制开销的一些常用方法。
让H指向列表的头部,T指向尾部,M指向中间。 (M可以在每次更改时保持时间O(1),如下所示。)初始化列表大小s = 0和mid-count m = 0。
对于您的操作1-6:
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}}。
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}}。
E peekMidElement(); [size()/ 2)+1]:如果是M,则返回M.e else null
E peekHighestElement():如果是H,则返回H.e(或T.e?),否则为null
E peekLowestElement():如果为T,则返回T.e(或H.e?),否则为null
int size():返回s
我不知道堆栈的哪一端是“高”;你认为它在成长或成长吗?无论如何,只需修复操作4& 5,如你所愿,并更改为peekHeadElement或peekFirstElement等名称。
答案 3 :(得分:0)
在这种情况下,数组实现是理想的,但我不确定您的描述是否仍然可以称为堆栈。实施时需要注意的一些要点如下:
按下数组的右侧。如果超出阵列容量,则可以分配新阵列,复制所有元素并删除以前的分配。所有这些都是由大多数语言中的一些基于数组的容器类自动处理的。但是,有一些方法可以避免大部分复制,同时扩展堆栈的容量,这可能会导致某些其他操作的效率降低。
如果你保留一个索引来标记下一个插入(即push(E e)),pop()可以像" - ;"那样简单实现。
peekMiddle()只是(size / 2)索引上的元素。我希望你不是要寻找中值。
对于peekLowest(),简单的解决方案是保持一堆最小值,即当你将一个值推入堆栈时,如果它是新的最小值,也将它推到最小堆栈上。这样,最小堆栈的最高值将是peekLowest()的答案。当然,当你从原始堆栈中弹出一个值时,如果它是最小值(由peekLowest()给出),也会从最小堆栈中弹出它。类似的方法可以用于peekHighest()。
通过这个简单的实现,您应该能够为所有操作获得O(1)运行时间。对于推(E e),O(1)是摊销的运行时间。