• 常见面试题之自我实现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的性能会更加好一些。

  • 相关阅读:
    二分图 洛谷P2055 [ZJOI2009]假期的宿舍
    并查集 洛谷P1640 [SCOI2010]连续攻击游戏
    贪心 洛谷P2870 Best Cow Line, Gold
    贪心 NOIP2013 积木大赛
    快速幂 NOIP2013 转圈游戏
    倍增LCA NOIP2013 货车运输
    树形DP 洛谷P2014 选课
    KMP UVA1328 Period
    动态规划入门 BZOJ 1270 雷涛的小猫
    KMP POJ 2752Seek the Name, Seek the Fame
  • 原文地址:https://www.cnblogs.com/leeqq/p/3940086.html
Copyright © 2020-2023  润新知