java主要集合類的資料結構學習
阿新 • • 發佈:2020-10-09
在程式中,集合類每天都在使用,以致於某些程式碼充斥著List和Map,一直沒有機會整理下它們背後的實現原理。這幾天不太忙,正好可以看會程式碼,補充下概念。
和集合類的大致分類類似,下面我也分List,Map和Set來描述。
一. List
1).ArrayList
ArrayList維護著一個物件陣列。如果呼叫new ArrayList()後,它會預設初始一個size=10的陣列。
每次add操作都要檢查陣列容量,如果不夠,重新設定一個初始容量1.5倍大小的新陣列,然後再把每個元素copy過去。
在陣列中間插入或刪除,都要移動後面的所有元素。(使用System.arraycopy())
2).LindedList
LinkedList的實現是一個雙向連結串列。每個節點除含有元素外,還包含向前,向後的指標。
新建一個LinkedList,生成一個頭節點(header,就是一個頭指標),它的元素為null。
它自包含,next和previous指標都指向自己。
執行add(Object obj)方法後,會生成一個新節點
Header節點的next指向連結串列的第一個節點,previous指向連結串列的最後一個節點,在這裡都是first。
再增加一個物件,它的形狀像下面這樣。
現在是一個標準的雙向連結串列形狀。每個節點都有自己的next和previous指標。
增加節點,只會對連結串列的指標進行操作,速度快
LinkedList實現了Deque,所以它有雙向佇列的特徵,在連結串列兩端可增刪資料
使用index查詢物件時,會以index和size/2比較,從前或從後向中間搜尋
ListIterator可向前或向後迭代
比較ArrayList和LinkedList的結構,就可以得出:
1. ArrayList的remove和add(index, Object)操作代價高,需要移動後面的每個元素。
2. LinkedList的get(index)操作代價高,它要先迴圈遍歷list,找到Object
二. Map
1).HashMap
HashMap的結構是一個雜湊桶,初始化時生成如下結構
每個bucket包含一個Entry(map自定義的一種結構,包含一個往後的指標)的連結串列。
在put(key, value)後,它的結構如下
將key的hashcode再次雜湊,然後用這個hash和length-1進行按位與操作,得到bucket的index,然後檢查當前bucket的連結串列,有沒有這個key,如果有替換value,沒有則跟在連結串列的最後。
允許key和value都可以是null
Index=0的bucket存key=null的value,也可以是其它hashcode為0的項
初始容量必須為2的冪次(我的理解是,在生成index的時候有這樣的程式碼:hase ^ (length - 1)),length – 1的二進位制程式碼為全1,則容易進行hash的設計)
如果兩個key雜湊後的index一樣的話,第一個key生成的Entry先存在桶中,第二個key生成的Entry會將第一個Entry設為自己的next,串起來。(如圖中,先put(yy, “first”),會將這個Entry設為bucket的第一項,後put(xx,”second”),則生成新Entry,它的next為key為yy的Entry,生成一個連結串列)
在put操作中,會比較threshold(capacity * load_factor,一個臨界值),如果size > threshold的話,生成一個當前bucket兩倍數量的buckets,然後把現有的資料重新雜湊到新bucket中
對HashMap迭代時,返回資料的順序是:index從0到length-1,迴圈遍歷每個bucket,把不為null的資料取出,每個bucket內的順序由連結串列的順序決定。而不是由插入資料決定。
2).LinkedHashMap
上面說過,Map的迭代不由插入順序決定。如果要保持這種順序呢?就要新增加一種結構來保持。
LinkedHashMap是HashMap的子類,增加一個雙向連結串列,用來儲存每個新加入的節點。在遍歷時,按連結串列的順序進行。其實差不多就是上面HashMap和LinkedList的和吧。
三. Set
1).HashSet
HashSet使用HashMap來保持元素。Key = 元素,value是一個公有的物件,對每個元素都一樣,在HashMap裡面key是惟一的,當然很適合於構造set集合。等同於用HashMap包裝了次,顯示Set自己的特性。
最後還要提到集合類裡面一個很重要的類:Collections,它有很多自己獨特的靜態方法。當然它主要提供幾種特殊集合(List, Map,Set),可以呼叫靜態方法來獲得:Unmodifiable*(不可修改集合,不可新增或刪除元素),Synchronize*(保持同步集合,它的基本每個方法都加鎖,防止併發操作),Checked*(宣告之始傳入特定型別,以後的操作都會驗證加入元素是否屬於已定型別),Singleton*(集合中只包含一個元素)。它們都是通過包裝集合類中的抽象類獲得,產生不同的行為。
上面是常見的幾種集合類,其它類我很少使用到。
不記得是誰說過,我們最容易記住影象化的知識。在學習了部分集合類知識後,總結下,以便以後忘記了還能翻看下。
和集合類的大致分類類似,下面我也分List,Map和Set來描述。
一. List
1).ArrayList
ArrayList維護著一個物件陣列。如果呼叫new ArrayList()後,它會預設初始一個size=10的陣列。
每次add操作都要檢查陣列容量,如果不夠,重新設定一個初始容量1.5倍大小的新陣列,然後再把每個元素copy過去。
在陣列中間插入或刪除,都要移動後面的所有元素。(使用System.arraycopy())
2).LindedList
LinkedList的實現是一個雙向連結串列。每個節點除含有元素外,還包含向前,向後的指標。
新建一個LinkedList,生成一個頭節點(header,就是一個頭指標),它的元素為null。
它自包含,next和previous指標都指向自己。
執行add(Object obj)方法後,會生成一個新節點
Header節點的next指向連結串列的第一個節點,previous指向連結串列的最後一個節點,在這裡都是first。
再增加一個物件,它的形狀像下面這樣。
現在是一個標準的雙向連結串列形狀。每個節點都有自己的next和previous指標。
增加節點,只會對連結串列的指標進行操作,速度快
使用index查詢物件時,會以index和size/2比較,從前或從後向中間搜尋
ListIterator可向前或向後迭代
比較ArrayList和LinkedList的結構,就可以得出:
1. ArrayList的remove和add(index, Object)操作代價高,需要移動後面的每個元素。
2. LinkedList的get(index)操作代價高,它要先迴圈遍歷list,找到Object
二. Map
1).HashMap
HashMap的結構是一個雜湊桶,初始化時生成如下結構
每個bucket包含一個Entry(map自定義的一種結構,包含一個往後的指標)的連結串列。
將key的hashcode再次雜湊,然後用這個hash和length-1進行按位與操作,得到bucket的index,然後檢查當前bucket的連結串列,有沒有這個key,如果有替換value,沒有則跟在連結串列的最後。
允許key和value都可以是null
Index=0的bucket存key=null的value,也可以是其它hashcode為0的項
初始容量必須為2的冪次(我的理解是,在生成index的時候有這樣的程式碼:hase ^ (length - 1)),length – 1的二進位制程式碼為全1,則容易進行hash的設計)
如果兩個key雜湊後的index一樣的話,第一個key生成的Entry先存在桶中,第二個key生成的Entry會將第一個Entry設為自己的next,串起來。(如圖中,先put(yy, “first”),會將這個Entry設為bucket的第一項,後put(xx,”second”),則生成新Entry,它的next為key為yy的Entry,生成一個連結串列)
在put操作中,會比較threshold(capacity * load_factor,一個臨界值),如果size > threshold的話,生成一個當前bucket兩倍數量的buckets,然後把現有的資料重新雜湊到新bucket中
對HashMap迭代時,返回資料的順序是:index從0到length-1,迴圈遍歷每個bucket,把不為null的資料取出,每個bucket內的順序由連結串列的順序決定。而不是由插入資料決定。
2).LinkedHashMap
上面說過,Map的迭代不由插入順序決定。如果要保持這種順序呢?就要新增加一種結構來保持。
LinkedHashMap是HashMap的子類,增加一個雙向連結串列,用來儲存每個新加入的節點。在遍歷時,按連結串列的順序進行。其實差不多就是上面HashMap和LinkedList的和吧。
三. Set
1).HashSet
HashSet使用HashMap來保持元素。Key = 元素,value是一個公有的物件,對每個元素都一樣,在HashMap裡面key是惟一的,當然很適合於構造set集合。等同於用HashMap包裝了次,顯示Set自己的特性。
最後還要提到集合類裡面一個很重要的類:Collections,它有很多自己獨特的靜態方法。當然它主要提供幾種特殊集合(List, Map,Set),可以呼叫靜態方法來獲得:Unmodifiable*(不可修改集合,不可新增或刪除元素),Synchronize*(保持同步集合,它的基本每個方法都加鎖,防止併發操作),Checked*(宣告之始傳入特定型別,以後的操作都會驗證加入元素是否屬於已定型別),Singleton*(集合中只包含一個元素)。它們都是通過包裝集合類中的抽象類獲得,產生不同的行為。
上面是常見的幾種集合類,其它類我很少使用到。
不記得是誰說過,我們最容易記住影象化的知識。在學習了部分集合類知識後,總結下,以便以後忘記了還能翻看下。
轉載於:https://my.oschina.net/boltwu/blog/715343