在程式設計的過程中,選擇何種集合至關重要,下面由我來總結下選擇集合的方法
選擇集合所考慮的關鍵問題在於:效率代價與空間代價的平衡問題。
效率代價是指執行的效率,簡單的說如果乙個資源沒有把索引記錄下來,那麼要找到他你就需要執行程式,那麼你的代價在於系統花錢了時間。
空間代價是指存放的空間消耗記憶體的代價,如上邊說到的如果把索引記錄下來很方便就能找到要找的資源,也就是用空間代價換取執行時間的縮短。這就像**本除了記號碼還要記人名,總不能乙個個打**去問誰是張三李四的吧。
我想說的是,現在的儲存器越來越便宜,空間可以說不是難題,空間代價不是優先考慮的問題。
下面我們來分析下各種常用的集合資料型別
1. arraylist:陣列實現的保持進入順序的集合。
查詢元素操作(提供索引位置):計算元素記憶體指標位置,一步便可跳到。
增加元素操作:查詢到增加位置的元素,後面的元素挨個向後移乙個位置,儲存元素的 時間可以忽略不計
刪除元素操作:查詢到增加位置的元素,後面的元素挨個向前移乙個位置,清空元素的時間可以忽略不計
修改元素操作:與查詢元素操作效率相同
2. linkedlist:鍊錶實現的保持進如順序的集合。
查詢元素操作(提供索引):從根節點遍歷,不能跳越,直到索引要求的位置。
增加元素操作:查詢到增加位置的元素,接上鏈的時間忽略不計
刪除元素操作:查詢到增加位置的元素,拆下鏈的時間忽略不計
修改元素操作:與查詢元素操作效率相同
3. hashset/hashmap:無序的hash演算法來索引的集合
查詢元素操作:hashcode經過hash演算法直接指向記憶體位址,而後呼叫指向的資料的equals(),如果不等,繼續hash演算法。
增加元素操作:查詢到增加位置的元素,儲存的時間忽略不計
刪除元素操作:查詢到增加位置的元素,刪除的時間忽略不計
修改元素操作:與查詢元素操作效率相同
4. treeset/treemap:根據指定值排序的集合,低層是鍊錶
查詢元素操作:紅黑二分查詢樹演算法,鍊錶遍歷跳過部分節點,效率大於linkedlist
增加元素操作:查詢到增加位置的元素,接上鏈的時間忽略不計
刪除元素操作:查詢到增加位置的元素,拆下鏈的時間忽略不計
修改元素操作:與查詢元素操作效率相同
效能分析表:
集合/操作
a增b刪
c查d改
順序性arraylist
c+④=a
=c進入順序
linkedlist
c+①=a
=c進入順序
hashset/hashmap
c+②=a
=c無順序
treeset/treemap
c+③=a
=c指定順序
注釋:=a表示效率上等於其a操作,也就是增操作,=c也同理;c+①表示查詢效率要加入計算。
從上面中最核心的問題是arraylist增刪操作與linkedlist查詢操作代價比較
案例1:arraylist與linkedlist的add/remove操作的比較
分析1:低效率arraylist.add/remaove操作的原因在於增刪操作可能會引起元素的交換,而linkedlist的增刪只需要接鏈頭和鏈尾。
結果資料1:arraylist的100萬次的交換消耗了3mm
案例2:arraylist與linkedlist的get操作的比較
分析2:linkedlist的查詢操作效率低的原因是必須遍歷過程中的每個節點,但是遍歷一次僅相當於getter方法呼叫消耗非常小。
結果資料2:linkedlist的166萬次的遍歷都消耗都不到1mm
結論:通過以上案例測試得知,遍歷元素與交換元素的效率差至少是十萬級的。所以我們幾乎可以忽略linkedlist查詢的效率,而hashset/hashmap,treeset/treemap效率比linkedlist還要高,也可以忽略其查詢效率。
由此,應修改效能分析表如下:
效能分析表:
集合/操作
a增b刪
c查d改
順序性arraylist
=a=c
進入順序
linkedlist
=a=c
進入順序
hashset/hashmap
=a=c
無順序treeset/treemap
=a=c
指定順序
總結:1:如果元素沒有順序要求,有優的選擇是hashset/hashmap,其增刪查詢的效率都很高。
2:如果元素有順序要求,對於arraylist、linkedlist和treeset/treemap都可以實現,只是arraylist、linkedlist需要控制進入順序,而treeset/treemap需要值記錄順序。如果記錄順序的值很方便提供,優先選擇treeset/treemap。
3:如上述有順序要求,而記錄順序的值不方便提供的情況,如stack,如果提供入棧時間比較冗餘。這個時候則考慮集合會不會出現元素順序改動的增刪操作,如果會則選擇linkedlist。如案例1,2中的結論arraylist的單位次交換耗時至少是linkedlist遍歷乙個節點的50萬倍以上。
4:如上述情況有順序要求,並且不希望提供值來排序,而且集合的順序基本不會發生改變,選擇arraylist。
選擇set還是map?
誤點1:map比set資料多出乙個維度,那麼就可以利用多出的部分影響順序或多出快捷收索功能。
正解1:原則是乙個集合物件只能提供乙個索引。
對於map其有效的索引則是key(實際上是key的equals和hashcode),而value是不能主導乙個條目的,如map的remove就不能通過value來刪除,map也不支援value找到key的方法(如果iterator遍歷找到key那就不能稱之為索引到)。
還是乙個真理乙個集合僅提供乙個索引,set和map的區別只在於,索引是否唯一且資料本身就可以提供。只有滿足這兩個條件才可以使用set。因為set有賴於元素本身的equals/hashcode和comparto方法,而這些方法只能由屬性運算得出結果,所以屬性要求有能力提供出索引。而set的元素型別一旦被確定,也就說用兩個set為同乙個資料加索引,其索引規則相同,這是因為元素類獨有乙份equals/hashcode和comparto方法的實現。
如果索引需要多個或資料物件的屬性沒有能力給出此索引,那麼我們會選擇map。map的key可以是我們定製的物件型別,也就是提供不同的equals/hashcode和comparto的方法實現,而不像set只能呼叫到資料本身的一種實現。選擇不同的key型別就會得到不同的方法實現,建立不同的索引,從而多個map能實現多個索引。
如果希望同乙個資料可能會被多種值檢索到,那麼就為他們各自建立乙個map,多個map多個索引方式。map總是能實現索引,而set只能提供自身的一種索引,set是map的特例情況。
如何選擇集合
在程式設計的過程中,選擇何種集合至關重要,下面由我來總結下選擇集合的方法 選擇集合所考慮的關鍵問題在於 效率代價與空間代價的平衡問題。效率代價是指執行的效率,簡單的說如果乙個資源沒有把索引記錄下來,那麼要找到他你就需要執行程式,那麼你的代價在於系統花錢了時間。空間代價是指存放的空間消耗記憶體的代價,...
Collection集合總結及如何選擇集合
collection集合總結 collection list 有序,可充復 arraylsit 底層資料結構是陣列,查詢快,增刪慢 執行緒不安全 效率高 vector 底層資料是陣列,查詢快增刪慢 執行緒安全,效率低 linledlsit 底層資料是鍊錶,查詢慢,增刪快 執行緒不安全 效率高 set...
C 集合類選擇
一定要謹慎選擇 system.collections 類。選用錯誤的型別可能限制您使用集合。考慮以下問題 您是否需要乙個序列列表,其中的元素通常在檢索其值後被放棄?如果需要,那麼在需要先進先出 fifo 行為時請考慮使用 queue 類或 queue 泛型類。在需要後進先出 lifo 行為時請考慮使...