集合總結--ArrayList、LinkedList、HashMap

 
1、概述
       ArrayList:數組集合。 查詢、修改、新增(尾部新增)快,刪除、新增(隊列中間)慢,適用於查詢、修改較多的場景。
       LinkedList:雙向鏈表集合。查詢、修改慢(須要遍歷集合),新增,刪除快(只須要修改先後節點的連接便可),適用於新增、刪除較多的場景。
       HashMap:結合數組和鏈表的優點,指望作到增刪改查都快速,時間複雜度接近於O(1)。當hash算法較好時,hash衝突較低。適用於增刪改查全部場景。
 
 
2、分敘
    ArrayList
  • ArrayList底層實現是基於數組的,所以對指定下標的查找和修改比較快,可是刪除和插入操做比較慢。算法

  • 構造ArrayList時儘可能指定容量,減小擴容時帶來的數組複製操做,若是不知道大小能夠賦值爲默認容量10。數組

  • 每次添加元素以前會檢查是否須要擴容,每次擴容都是增長原有容量的一半。(擴容是建立一個新的數組,並將原來的數組元素遷移到新數組中)安全

  • 每次對下標的操做都會進行安全性檢查,若是出現數組越界就當即拋出異常。數據結構

  • ArrayList的全部方法都沒有進行同步,所以它不是線程安全的多線程

  • 以上分析基於JDK1.7,其餘版本會有些出入,所以不能一律而論函數

 
    LinkedList
   數據結構
private static class Node<E> {
  E item;          //元素
  Node<E> next;    //下一個節點
  Node<E> prev;    //上一個節點

  Node(Node<E> prev, E element, Node<E> next) {
      this.item = element;
      this.next = next;
      this.prev = prev;
  }
}
  • LinkedList是基於雙向鏈表實現的,不管是增刪改查方法仍是隊列和棧的實現,均可經過操做結點實現性能

  • LinkedList無需提早指定容量,由於基於鏈表操做,集合的容量隨着元素的加入自動增長(無需執行默認長度,也沒有擴容需求)this

  • LinkedList刪除元素後集合佔用的內存自動縮小,無需像ArrayList同樣調用trimToSize()方法spa

  • LinkedList的全部方法沒有進行同步,所以它也不是線程安全的,應該避免在多線程環境下使用線程

  • LinkedList根據index查詢時採起的是二分法,即index小於總長度一半時從鏈表頭開始日後查找,大於總長度一半時從鏈表尾往前查找。若是是根據元素查找,則須要從頭開始遍歷

  • 以上分析基於JDK1.7,其餘版本會有些出入,所以不能一律而論。

 
 
  HashMap
  數據結構
static class Entry<K,V> implements Map.Entry<K,V> {
  final K key;      //
  V value;          //
  Entry<K,V> next;  //下一個Entry的引用
  int hash;        //哈希碼
 
  ...              //省略下面代碼
}
  哈希圖
    • 哈希表是由數組和單項鍊表共同構成的一種結構,上圖中一個數組元素鏈表存在多個元素,說明存在hash衝突,理想狀況下每一個數組元素只應包含一個元素
    • 擴容緣由:HashMap默認的初始容量爲16,默認的加載因子是0.75。而threshold是集合可以存儲的鍵值對的閥值,默認是初始容量*加載因子,也就是16*0.75=12,當鍵值對要超過閥值時,意味着這時候的哈希表已處於飽和狀態,再繼續添加元素就會增長哈希衝突,從而使HashMap的性能降低。
    • 每次擴容都是增長原有容量的一倍。(擴容是建立一個新的數組,並將原來的數組元素遷移到新數組中,根據hash值從新分配)
    • hash值的計算方式(字符串是單獨的計算方式,擾動函數就是把全部東西雜糅到一塊兒,提升隨機性
//生成hash碼的函數
final int hash(Object k) {
  int h = hashSeed;
  //key是String類型的就使用另外的哈希算法
  if (0 != h && k instanceof String) {
      return sun.misc.Hashing.stringHash32((String) k);
  }
  h ^= k.hashCode();
  //擾動函數
  h ^= (h >>> 20) ^ (h >>> 12);
  return h ^ (h >>> 7) ^ (h >>> 4);
}
 
 
3、總結
       概述中已經描述各個集合的適用場景,這裏重點說一下HashMap。HashMap能夠經過hash值快速定位到數組下標,執行新增、修改、刪除操做。當hash算法較好(hash衝突較少)時,增刪改查的時間複雜度都是O(1)。可是若是鏈表較長,則會增長增刪改查的時間複雜度O(鏈表長度)。原則就是儘可能減小hash衝突,並預先估算hashmap長度,減小擴容操做。
相關文章
相關標籤/搜索