ArrayList,LinkedList

ArrayList

ArrayList就是动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了动态的增加和减少元素,实现了Collection和List接口,灵活的设置数组的大小等好处。 ——《百度》

优点:
1.可以自动改变大小
2.可以灵活地插入删除元素,设置数组大小
局限性:
1.线程不安全
2.比一般数组速度慢

ArrayList的继承关系:
这里写图片描述

默认初始化容量大小:10

private static final int DEFAULT_CAPACITY = 10;

构造方法

   /**
     *用指定的初始容量构造一个空列表。
     */
public ArrayList(int initialCapacity) {
   super();
   //如果用户初始化大小小于0抛异常
   if (initialCapacity < 0)
   throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
   //建立一个Object数组
   this.elementData = new Object[initialCapacity];
}

    /**
     * 构造一个空列表,初始容量为10。
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

    /**
     * 按照集合的迭代器返回的顺序,构造一个包含指定集合元素的列表
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        //当c.toArray返回的不是Object类型数组时将数组拷贝
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

扩容

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //将容量扩展为原容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //扩容后的容量小于所需要的最小容量时,扩容容量赋值为最小容量的值
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //扩容后容量大于MAX_ARRAY_SIZE时,当所需最小容量大于MAX_ARRAY_SIZE,扩容容量赋值为Integer.MAX_VALUE否则赋值为MAX_ARRAY_SIZE
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) 
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

查找字符串位置(对null需要单独查找)

/*
*查找字符串第一次出现的位置
*/
    public int indexOf(Object o) {
        //对null单独查找,找到null时返回下标
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
        //不为null时,找到相同的返回下标
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        //找不到时返回-1
        return -1;
    }
/*
*查找字符串最后一次出现的位置
*/
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

clone()

    public Object clone() {
        try {
            @SuppressWarnings("unchecked")
                ArrayList<E> v = (ArrayList<E>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            throw new InternalError();
        }
    }

获取列表中指定位置的元素

    public E get(int index) {
        rangeCheck(index);
        //返回下标对应的元素
        return elementData(index);
    }

用指定的元素替换这个列表中指定位置的元素,并返回被替代的元素

    public E set(int index, E element) {
        rangeCheck(index);
        //将指定位置元素放入oldValue中,将指定元素放入指定位置,返回指定位置原本的元素
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

插入元素(插入时,先插入,再size++)

/*
*将元素插入在末尾
*/
    public boolean add(E e) {
        ensureCapacityInternal(size + 1); 
        //将指定元素放入size标记的位置,size++
        elementData[size++] = e;
        return true;
    }
/*
*将元素插入在指定位置
*/
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1); 
        //将elementData数组中,从index号位置开始的size-index位copy到elementData中从index+1号位置开始
        System.arraycopy(elementData, index, elementData, index + 1,
           size - index);
        //将指定元素放入数组的index位,然后size++
        elementData[index] = element;
        size++;
    }

插入集合中的全部元素

/*
*将集合中全部的元素插入到末尾
*/
   public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        //要插入的位数
        int numNew = a.length;
        ensureCapacityInternal(size + numNew); 
        //将数组a从0号下标开始的numNew位copy到elementData数组中从size下标开始,size=size+numNew
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }
/*
*将集合中全部的元素插入到指定位置
*/
      public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew); 
        //要移动的位数
        int numMoved = size - index;
        if (numMoved > 0)
        //进行移动
            System.arraycopy(elementData, index, elementData, index + numNew,
            numMoved);
        //将要插入的元素放入,然后size=size+numNew
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

删除(删除时,先size–,再制空size)

/*
*删除指定位置的元素,并返回该元素
*/
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        //将index后的元素向前移动
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
            numMoved);
        //先size--,再将size制空
        elementData[--size] = null;
        return oldValue;
    }
/*
*删除第一次出现的指定元素
*/
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }


    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null;
    }
/*
*删除指定范围的元素
*/
   protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        //要移动的位数
        int numMoved = size - toIndex;
        将从toIndex开始的numNew位移动到fromIndex开始
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

       //先将新size值改变,再将删除位制空,再将值赋给size
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }
    /*
    *从这个列表中删除所有包含在指定集合中的元素 
    */
     public boolean removeAll(Collection<?> c) {
        return batchRemove(c, false);
    }

/*
*只保留包含在指定集合中的元素
*/
   public boolean retainAll(Collection<?> c) {
        return batchRemove(c, true);
    }
/*
*根据(c.contains(elementData[r]) == complement)保存所需要的元素
*/
  private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

LinkedList

LinkedList 是一个双向链表。它也可以被当作堆栈、队列或双端队列进行操作。

LinkedList 是一个继承于AbstractSequentialList的双向链表。 实现了 List 接口,能对它进行队列操作。实现了Deque 接口,即能将LinkedList当作双端队列使用。实现了Cloneable接口,即覆盖了函数clone(),能克隆。实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。LinkedList 不是线程安全的。
LinkedList的继承关系:
这里写图片描述
构造函数

//默认构造函数,构造一个空列表
    public LinkedList() {
    }
//构造一个包含指定集合的列表
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

元素的获取

// 获取LinkedList的第一个元素
    public E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }


// 获取LinkedList的最后一个元素
    public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
    }

删除元素

 // 删除LinkedList的第一个元素
    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

    // 删除LinkedList的最后一个元素
    public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }

//删除指定元素
  public boolean remove(Object o) {
  //对null单独查找
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
        //不为空时,在链表中查找与指定元素相同的元素,删除
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }
 //删除指定位置的元素
        public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

添加元素

    // 将元素添加到LinkedList的起始位置
    public void addFirst(E e) {
        linkFirst(e);
    }

     // 将元素添加到LinkedList的结束位置
    public void addLast(E e) {
        linkLast(e);
    }
    //将元素添加到LinkedList的结束位置,返回值为布尔类型
        public boolean add(E e) {
        linkLast(e);
        return true;
    }
//将集合全部添加到LinkedList中
  public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }
    //用头插法插入全部元素
public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }

        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }
//在指定位置添加指定元素
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }
//向链表尾增添元素
    public boolean offer(E e) {
        return add(e);
    }
//向链表表头增添元素,成功返回true
        public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }
//向链表表尾增添元素,成功返回true
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }

判断LinkedList是否包含元素(o)

       public boolean contains(Object o) {
        return indexOf(o) != -1;
    }

返回LinkedList的大小

    public int size() {
        return size;
    }

清空链表

    public void clear() {
        for (Node<E> x = first; x != null; ) {
            Node<E> next = x.next;
            x.item = null;
            x.next = null;
            x.prev = null;
            x = next;
        }
        first = last = null;
        size = 0;
        modCount++;
    }

返回LinkedList指定位置的元素

    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

设置index位置对应的节点的值为element,并返回index位置原本的值

   public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }

获取指定位置的节点

    Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

查找节点所在位置

//从前向后查找
    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }
    //从后往前查找
        public int lastIndexOf(Object o) {
        int index = size;
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (x.item == null)
                    return index;
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (o.equals(x.item))
                    return index;
            }
        }
        return -1;
    }

返回第一个节点,但不删除

//链表为空则返回null
   public E peek() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }

 //链表为空则抛出异常 
   public E element() {
        return getFirst();
    }

返回第一个节点,并删除

//链表为空则返回null
    public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
     //链表为空则抛出异常 
    public E remove() {
    return removeFirst();
    }

ArrayList与LinkedList分别适合什么应用用场景
ArrayList:查询,ArrayList查询快是因为底层是由数组实现,通过下标定位数据快。写数据慢是因为复制数组耗时。
LinkedList:写数据,LinkedList底层是双向链表,查询数据依次遍历慢。写数据只需修改指针引用。

猜你喜欢

转载自blog.csdn.net/mars1997/article/details/81154438
今日推荐