我已经读过某个地方,ArrayList的 add()和 remove()操作在“分摊的常量”时间内运行。这究竟意味着什么?
在 add(item)的实现中,我可以看到它ArrayList使用的数组缓冲区最多只有list't大小的3/2,如果它已满,<调用em> System.arraycopy(),它应该在O(n)中执行,而不是O(1)时间。那么System.arraycopy是否尝试做一些比将元素逐个复制到新创建的数组更聪明的事情,因为时间实际上是O(1)?
结论: add(item)以分摊的常量时间运行,但添加(项目,索引)和删除(索引) don' t,它们以线性时间运行(如答案中所述)。
答案 0 :(得分:7)
我已经读过某个地方,ArrayList的add()和remove()操作在“amortized constant”时间内运行。
除非在特殊条件下,我认为remove()
不是这样。
remove(Object)
对随机元素的调用平均需要在列表中的一半条目上调用equals
,然后复制另一半的引用。
平均remove(int)
调用一个随机元素必须复制一半元素的引用。
remove(...)
平均O(1)
(例如摊销)的唯一情况是当您使用remove(int)
从列表末尾删除一些常量偏移的元素时。
答案 1 :(得分:3)
“摊销”大致意味着“在整个运行时间内平均”。是的,数组副本将是O(n)。但这只会在列表已满时发生,这种情况会发生在n次中。
答案 2 :(得分:0)
我认为,摊销的常数时间只是意味着如果你做大量的操作,它几乎是恒定的时间。因此,在一个测试中,一百万个项目列表,然后在另一个测试中添加两百万个项目到列表中。后者应比前者慢约2倍,因此,摊销时间不变。
答案 3 :(得分:0)
摊销的常数时间与常数时间不同。
基本上分摊的O(1)表示在n次操作中,任何操作的平均运行时间为O(1)。
对于数组列表,它的工作方式如下:
(O(1)insert + O(1)insert + ... + O(n)array copy)/ n operations = O(1)
答案 4 :(得分:0)
深入描述线程Constant Amortized Time
中的分摊常数的含义答案 5 :(得分:0)
摊销时间用简单的术语解释:
如果你做了一百万次的操作,你并不真正关心那个操作的最坏情况或最好的情况 - 你关心的是你重复操作时需要多少时间一百万次。
因此,如果操作偶尔非常缓慢并不重要,只要“偶尔”很少,以至于慢速被稀释掉。基本上摊还的时间意味着“如果你做很多操作,每次操作需要的平均时间”。摊销时间不必保持不变;你可以有线性和对数的摊销时间或其他任何东西。
让我们采用垫子的动态数组示例,您可以重复添加新项目。通常添加项目需要恒定的时间(即O(1))。但是每次数组都满了,你会分配两倍的空间,将数据复制到新区域,并释放旧空间。假设分配和释放在恒定时间内运行,这个放大过程需要O(n)时间,其中n是数组的当前大小。
所以每次放大时,你花费的时间大约是最后一次放大的两倍。但是你在做这件事之前也等了两倍!因此,每次放大的成本可以在插入中“展开”。这意味着从长远来看,将m个项目添加到数组所需的总时间为O(m),因此摊销时间(即每次插入的时间)为O(1)。