集合总结--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长度,减小扩容操做。
相关文章
相关标签/搜索