![](/img/trans.png)
[英]How is the Hashtable get(kType key) amortized time complexity O(1) and not O(log n)?
[英]How is the ArrayList add(Type value) method O(1) amortized time complexity?
ArrayList 的大多數實現在內部使用數組,並且當在向列表中添加元素時大小已經用完時,它通過基本上執行以下操作來調整大小或“增長”:
N - 1
設置為元素對象,其中N
是數組的新大小。 提供的解釋是,增加列表對於您的平均添加操作來說是一種罕見的必要性,因此平均添加的時間復雜度為O(1)
,因此攤銷常數時間。
我很困惑這是如何理解的。 假設列表增長Q
。 簡單的算術級數將告訴您,如果我將x
元素添加到 ArrayList 中,如果x
比Q
大幾倍,則內部完成的元素副本總數為x^2 + Qx / 2Q
。
當然,對於添加的前幾個值,時間很可能是恆定的,但是對於添加的足夠多的元素,我們看到每個添加操作的平均時間復雜度為線性或O(n)
。 因此,向列表中添加大量元素需要指數時間。 我不明白即使是單個添加操作的攤銷時間復雜度也是恆定的。 有什么我想念的嗎?
編輯:我沒有意識到列表增長實際上是幾何的,這優化了攤銷時間復雜度。
結論:
動態列表的線性增長
讓N = kQ
對於N + 1
插入
副本:
Q + 2Q + 3Q + … + kQ
= (k / 2)(2Q + (k - 1)Q)
= (k / 2)(Q + kQ)
= (kQ + k^2 * Q) / 2
-> kQ + k^2 * Q
元素初始化:
Q + 2Q + 3Q + 4Q + … + (k + 1) * Q
= ((k + 1) / 2)(2Q + kQ)
= (k^2 * Q + 2kQ + 2Q + kQ) / 2
-> k^2 * Q + 3kQ + 2Q
廉價插入:
kQ + 1
-> kQ
總成本: 2Q * k^2 + 5kQ + 2Q
每次插入的攤銷成本:
2k + 5 + 2 / k
-> 2k + 2 / k
-> O(N / Q)
-> O(N)
動態列表的幾何增長
讓N = Q^k
對於N + 1
插入
副本:
1 + Q + Q^2 + … + Q^k
= (1 - Q^(k + 1)) / (1 - Q)
-> Q^k
元素初始化:
1 + Q + Q^2 + … + Q^(k + 1)
= (1 - Q^(k + 2)) / (1 - Q)
-> Q^(k + 1)
廉價插入:
Q^k + 1
-> Q^k
總成本: 2Q^k + Q^(k + 1)
每次插入的攤銷成本:
2 + Q
-> O(1)
比較
數組的幾何大小調整/增長是恆定時間,而線性調整大小是線性時間。 比較兩種增長方法以查看性能差異以及為什么選擇 ArrayList 以幾何方式增長是很有趣的。
不失一般性,假設列表的初始容量為 1。我們進一步假設每次插入超過容量時容量加倍。 現在考慮插入2^k + 1
元素(這是最壞的情況,因為最后一個操作觸發了動態增長)。
有k
插入觸發動態增長,它們的累積成本為
1 + 2 + 4 + 8 + ... + 2^k = 2^(k+1) - 1
其他“廉價”插入的累積成本是2^k - k + 1
。
但是我們對攤銷復雜度感興趣,因此我們必須對所有2^k + 1
操作求平均值:
(2^(k+1) + 2^k - k) / (2^k + 1)
< (2^(k+1) + 2^k - k) / 2^k
= 2 + 1 - k/2^k
= O(1)
因此,向列表中插入2^(k+1)
元素具有每次插入的攤銷時間復雜度為 O(1),並且常數因子接近 3。向列表中插入任何其他數量的元素都不會更糟,因此攤銷的時間復雜度為每次插入的時間復雜度通常為 O(1)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.