常见面试题之自我实现ArrayList & LinkedList

面试者经常遇到集合类源码的问题。我们不求将所有的细节都记住,但ArrayList与LinkedList比较、add、get、remove、扩容、及相关时间复杂度等核心思想要说得一清二楚。

ArrayList底层用数组实现,可以快速访问某一节点的值,但插入删除会调用System.arraycopy方法,数组容量不够时需进行扩容,扩容采用新的大数组取代旧的数组。

 

public class MyArrayList<E> {

  private Object[] elementData;

  public int size;// 数组中元素长度

  private static final int INITIAL_CAPACITY = 10;// 初始容量

  public MyArrayList() {
    elementData = new Object[INITIAL_CAPACITY];
  }

  public MyArrayList(int capacity) {
    elementData = new Object[capacity];
  }

  private void ensureCapacity(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
      int newCapacity = (oldCapacity * 3) / 2 + 1;
      if (newCapacity < minCapacity)
        newCapacity = minCapacity;
      elementData = Arrays.copyOf(elementData, newCapacity);// 扩容调用Arrays.copyOf方法 将容量扩为原数组长度的3/2, 现有的数组引用指向了新的数组
                                      // 时间复杂度为O(n)
    }
  }

  // 在數組末尾添加元素 時間複雜度O(1)
  public void add(E e) {
  if (e == null)
    return;
  ensureCapacity(size + 1);
  elementData[size++] = e;
  }

  public void add(E e, int index) {
    if (e == null || index > size || index < 0)
      return;
    ensureCapacity(size + 1);
    System.arraycopy(elementData, index, elementData, index + 1, size - index);  // 数组中间添加元素
                                              //平均时间复杂度O(n)
                
    elementData[index] = e;
    size++;
  }

  public E get(int index) {
    if (index > size || index < 0)
      return null;
    return (E) elementData[index]; // 按位置获取元素 时间复杂度为O(1)public class MyArrayList<E> {

  private Object[] elementData;

  public int size;// 数组中元素长度

  private static final int INITIAL_CAPACITY = 10;// 初始容量

  public MyArrayList() {
    elementData = new Object[INITIAL_CAPACITY];
  }

  public MyArrayList(int capacity) {
    elementData = new Object[capacity];
  }

  private void ensureCapacity(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
      int newCapacity = (oldCapacity * 3) / 2 + 1;
      if (newCapacity < minCapacity)
        newCapacity = minCapacity;
      elementData = Arrays.copyOf(elementData, newCapacity);// 扩容调用Arrays.copyOf方法 将容量扩为原数组长度的3/2, 现有的数组引用指向了新的数组
                                      // 时间复杂度为O(n)
    }
  }

  // 在數組末尾添加元素 時間複雜度O(1)
  public void add(E e) {
  if (e == null)
    return;
  ensureCapacity(size + 1);
  elementData[size++] = e;
  }

  public void add(E e, int index) {
    if (e == null || index > size || index < 0)
      return;
    ensureCapacity(size + 1);
    System.arraycopy(elementData, index, elementData, index + 1, size - index);  // 数组中间添加元素
                                              //平均时间复杂度O(n)
                
    elementData[index] = e;
    size++;
  }

  public E get(int index) {
    if (index > size || index < 0)
      return null;
    return (E) elementData[index]; // 按位置获取元素 时间复杂度为O(1)
  }

  public E remove(int index) {
    if (index > size || index < 0)
      return null;
    E oldValue = get(index);
    int numMoved = size - index - 1;
    if (numMoved > 0) // 删除元素 平均复杂度为O(n)
      System.arraycopy(elementData, index + 1, elementData, index,
              numMoved);
    elementData[--size] = null;
    return oldValue;
  }
}
  }

  public E remove(int index) {
    if (index > size || index < 0)
      return null;
    E oldValue = get(index);
    int numMoved = size - index - 1;
    if (numMoved > 0) // 删除元素 平均复杂度为O(n)
      System.arraycopy(elementData, index + 1, elementData, index,
              numMoved);
    elementData[--size] = null;
    return oldValue;
  }
}

 

可见,ArrayList可以根据索引快速访问任意元素,但插入、删除、扩容操作会调用System.arrayCopy()方法,这是个非常占用系统资源的操作。当你遇到访问元素比插入或者是删除元素更加频繁的时候,你应该使用ArrayList,在频繁的插入或者是删除元素的情况下,LinkedList的性能会更加好一些。

posted @ 2014-08-28 15:39  常山赵子龙lzq  阅读(300)  评论(0编辑  收藏  举报