在程式設計的過程中,選擇何種集合至關重要,下面由我來總結下選擇集合的方法
選擇集合所考慮的關鍵問題在於:效率代價與空間代價的平衡問題。
效率代價是指執行的效率,簡單的說如果乙個資源沒有把索引記錄下來,那麼要找到他你就需要執行程式,那麼你的代價在於系統花錢了時間。
空間代價是指存放的空間消耗記憶體的代價,如上邊說到的如果把索引記錄下來很方便就能找到要找的資源,也就是用空間代價換取執行時間的縮短。這就像**本除了記號碼還要記人名,總不能乙個個打**去問誰是張三李四的吧。
我想說的是,現在的儲存器越來越便宜,空間可以說不是難題,空間代價不是優先考慮的問題。
下面我們來分析下各種常用的集合資料型別
1.arraylist:
陣列實現的保持進入順序的集合。
查詢元素操作
(提供索引位置
):計算元素記憶體指標位置,一步便可跳到。
增加元素操作:查詢到增加位置的元素,後面的元素挨個向後移乙個位置,儲存元素的
時間可以忽略不計
刪除元素操作:查詢到增加位置的元素,後面的元素挨個向前移乙個位置,清空元素的時間可以忽略不計
修改元素操作:與查詢元素操作效率相同
2.linkedlist:
鍊錶實現的保持進如順序的集合。
查詢元素操作
(提供索引
):從根節點遍歷,不能跳越,直到索引要求的位置。
增加元素操作:查詢到增加位置的元素,接上鏈的時間忽略不計
刪除元素操作:查詢到增加位置的元素,拆下鏈的時間忽略不計
修改元素操作:與查詢元素操作效率相同
3.hashset/hashmap:
無序的hash
演算法來索引的集合
查詢元素操作:
hashcode
經過hash
演算法直接指向記憶體位址,而後呼叫指向的資料的
equals()
,如果不等,繼續
hash
演算法。增加元素操作:查詢到增加位置的元素,儲存的時間忽略不計
刪除元素操作:查詢到增加位置的元素,刪除的時間忽略不計
修改元素操作:與查詢元素操作效率相同
4.treeset/treemap:
根據指定值排序的集合,低層是鍊錶
查詢元素操作:紅黑二分查詢樹演算法,鍊錶遍歷跳過部分節點,效率大於
linkedlist
增加元素操作:查詢到增加位置的元素,接上鏈的時間忽略不計
刪除元素操作:查詢到增加位置的元素,拆下鏈的時間忽略不計
修改元素操作:與查詢元素操作效率相同
效能分析表:集合/
操作a增b
刪c查d
改順序性
arraylistc+④
=a①=c進入順序
linkedlistc+①
=a④=c進入順序
hashset/hashmapc+②
=a②=c無順序
treeset/treemapc+③
=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 行為時請考慮使...