![](/img/trans.png)
[英]What happens if I don't specify StringLength or MaxLength on a string property?
[英]What is the order of complexity of inserting N elements into a List<T> if I don't specify a capacity?
假設我有類似的東西
List<int>() numbers = new List<int>();
int num;
while(int.TryParse(Console.ReadLine(), out num))
{
numbers.Add(num);
}
假設添加的元素數為N
考慮到插入通常是O(1)
而是O(n)
的事實,我想知道總復雜度是描述為O(N)
還是O(N^2)
。一會兒”內部需要將列表復制到更大的數組中。
.net使用一種算法的變體,當列表已滿時,該數組將分配一個兩倍大的數組,將現有元素復制到其中,並釋放舊元素,從而基本上擴展了初始數組。
實際上,所有提供列表等效項的語言都可能這樣做,因為沒有理由不這樣做。
並假設添加的元素數為N。我想知道當考慮到插入通常是O(1)時,總復雜度是O(N)還是O(N ^ 2)。 ),但當內部需要將列表復制到更大的數組中時,將“偶爾”顯示O(n)。
這是用於插入n
元素的攤銷O(n)
,是用於插入一個元素的攤銷O(1)
。
基本上,攤銷意味着插入n
元素的操作總數平均為O(n)
,即使由於插入必須擴展數組,一次插入操作可能比另一次執行更多的操作。
要看到這一點,請考慮我在第一段中描述的經典算法。 假設我們的容量最初為1。我們將計算擴展數組時執行的操作數。 插入第一個元素時,我們有:
0
操作,因為數組未擴展。
插入第二個元素必須將現有元素復制到新數組,然后才執行插入。 為了清楚起見,我們將忽略內存操作引入的常量。 因此,這是:
1
操作(復制1個元素,新容量為2)。
當插入第三個元素時,我們有:
2
操作(復制2個元素,新容量為4)
插入第四個元素時,我們有0
操作,因為我們還有剩余空間。
當插入第五個時,我們有:
4
操作(復制4個元素,新容量為8)。
通常,當插入第2^k+1
個元素時,我們將具有:
2^k
操作。
k
可以是多少? log base 2 of n
( log n
),因為這樣我們將有足夠的空間容納n
元素。
因此,所有調整大小操作的復雜度由總和給出:
S = 1 + 2 + 4 + ... + 2^k, k = log n
S = (1 - 2^k) / (1 - 2) // sum of a geometric progression with ratio 2
= 2^k - 1
= 2^(log n) - 1
= n - 1
= O(n)
因此總復雜度為O(n)
加上另一個O(n)
因為我們沒有計算實際的插入數。 但這仍然是O(n)
。
這完全取決於在此框架實例上運行的List實例將如何增長。 我無法預料的是,答案可能會因操作系統資源,框架版本和列表的完整程度而有所不同。 這是一個實現細節。
顯然,提供能力會提高性能。 如果您不確定確切的數目,則可以設置多余的容量,然后在全部添加之后使用TrimExcess() 。 容量只是為了避免必須增加列表的開銷。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.