Array、List的區別
Array—是基於索引(index)的數據結構,它使用索引在數組中搜索和讀取數據是很快的。Array獲取數據的時間複雜度是O(1),但是要刪除數據卻是開銷很大的,因爲這需要重排數組中的所有數據。
List—是一個有序的集合,可以包含重複的元素,提供了按索引訪問的方式,它繼承Collection。
Array和List都屬於順序表。
Array是一段連續的存儲結構
int[] i=new int[3]i 其實記錄的是數組的首地址,而i[1]其實相當於在i的地址的基礎上加上1個整數的地址偏移,然後再取這塊地址中的值。
List則是不連續的存儲結構, List的每個節點都有着一個Next屬性,這個屬性則記錄着他的下一個節點的地址。
也就是說當我們想找第100個節點的時候,他還是需要從第一個節點,然後做99次Next操作,才能找到list[99]節點。
在查找一個元素時時分別生成以下IL碼
Array:IL_0020: ldloc.0
IL_0021: ldc.i4.3
IL_0022: ldelem.i4
IL_0023: stloc.2
List:
IL_0022: ldloc.0
IL_0023: ldc.i4.3
IL_0024: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
IL_0029: stloc.2
通過這兩段IL,我只是希望證明List和Array對索引元素的方式是不同的。當然,我們無從知道Microsoft對List方法get_Item的實現。但是我們不難想象:
因爲List是一個鏈表,所以我需要從第一個元素開始逐個Next到所需索引的元素。這是一個耗時的過程。
1. 從空間擴展角度上來說:
數組必須要在初始化時分配固定的大小,比如說int[] a=new int[3];如果我們僅僅寫int[] a=new int[];編譯器就會無情地給我們報錯。但是List由於空間不必連續,所以無須指定初始大小。
總結1: 當不確定大小時,最好使用List 代替Array。
2. 從操作角度上來看:
關於索引這個就不贅述了。
總結2:當需要大量的查找操作時,最好使用Array。
對於插入(刪除)操作,很多人是從插入(刪除)的時間上分析,說List優於Array,我覺得是不合理的。
更合理的解釋應該是從兩個角度分析(以插入爲例):
<1> 指定位置插入指定元素:
對於Array講,有兩套解決方案:
A. 使用一個新數組,N+1個元素重新賦值的過程。一個for循環,時間複雜度O(n)。
B. 在原數組上操作,那麼首先需要爲該數組預留空間,這是個很難辦的事情。而且其後續元素的移動耗費時間複雜度仍未O(n)。
對於List來講,很多人說複雜度就是O(1)。這其實是不合理的,因爲List插入元素固然容易,但是在指定位置的插入,需要一個時間複雜度爲O(n)的查找過程。
但是隻考慮時間複雜度是不夠的,我們要考慮總體的情況。如果使用新數組,不僅浪費了新的空間,而且需要反覆的賦值過程,是N+1次。如果不使用新數組,預留空間實在太麻煩,因此綜上所述,還是List好。
<2> 給出前一個節點,然後在後面插入元素。這個我的意思就是不僅僅給出了PreviousNode的Value,還給出了他的Next。這個情況我就不廢話了,List的優勢太大了。可是在實際情況中,這種情況的可能性幾乎爲零。
因此,總結3:當需要進行頻繁的插入,刪除操作時,最好使用List代替Array。
另外,給出個不太重要的補充,由於List需要存儲他下一個節點的地址,所以List 比Array相對起來浪費了更多的空間。
也就是說雖然使用list<T>強類型範性,能夠節約裝箱拆箱時間,但查詢速度會有很多問題。
在實際使用中,對變化不大,查詢次數頻繁的,我們應該考慮list<T>外的情況
當然,就查詢某個值的速度而言,還是 Hashtable 或 Dictionary 最快,當然這兩者和我們在討論的東西,結構完全不相同,沒有可比性。畢竟數組,是節約空間,而hash表是散列的,犧牲空間來換取速度