我已经读过可以使用双倍数组实现缓存不经意的堆栈。
有人可以解释一下分析如何使每个推送和弹出具有1/B
摊销的I / O复杂性吗?
答案 0 :(得分:3)
堆栈支持以下操作:
虽然这两个操作可以使用带有O(1)push和O(1)pop的单链表执行,但它会遇到缓存问题,因为存储的元素通过内存分散。对于这种方法,我们将推到列表的前面,然后从列表的前面弹出。
我们可以使用dynamic array作为我们的数据结构,然后按下并弹出到数组的末尾。 (我们将跟踪数组中最后填充的位置作为索引,并在推送和弹出元素时对其进行修改)。
弹出将是O(1),因为我们不需要调整数组的大小。
如果阵列末尾有一个额外的空格,推送将为O(1)。
问题是当我们尝试推送元素但没有空间时。在这种情况下,我们创建一个两倍大(2n)的新数组,然后复制n个元素中的每一个,然后推送元素。
假设我们有一个已经大小为n的数组,但是从空开始。
如果我将n + 1个元素推到数组上,那么前n个元素需要O(1)* n = O(n)时间。
+1元素花费O(n)时间,因为它必须构建数组的新副本。
因此将n + 1个元素推入数组是O(2n),但是我们可以去除常量,只是说它是元素数的O(n)或线性。
因此,推动单个元素可能需要比常量操作更长的时间,推动大量元素需要花费大量工作。
动态数组是缓存友好的,因为所有元素尽可能彼此接近,因此多个元素应位于相同的缓存行中。
答案 1 :(得分:1)
我认为标准堆栈是缓存无关紧要的。您只有1 / B的访问故障,因为任何推/弹序列必须是相邻的地址,因此每B操作只能命中一个新的缓存行。 (注意:参数需要至少2个缓存行以防止颠簸。)