Collection的子接口之【List】

目录

List自身提供了和index相关的方法

List的特点

List的常见实现类

ArrayList

底层数据结构是数组

懒加载的体现

最大容量为int类型的最大值

扩容机制

使用equals方法来判断是否包含某个元素

随机增删元素效率较低,需要移动元素,时间复杂度为O(n)

LinkedList

底层数据结构是双向链表

add(E e)和remove()方法

获取元素需要遍历节点,效率较低,时间复杂度为O(n)

随机增删元素效率高,只需要改变指针指向即可,时间复杂度为O(1)

可以用作栈

可以用作队列

本身就是双向队列


List自身提供了和index相关的方法

package java.util;

public interface List extends Collection {
    // ...

    boolean addAll(int index, Collection c);

    E get(int index);

    E set(int index, E element);
    
    void add(int index, E element);

    E remove(int index);

    // ...
}

List的特点

  • 元素添加位置有序性
  • 元素可以重复

List的常见实现类

Collection的子接口之【List】_第1张图片

ArrayList

底层数据结构是数组

//使用数组存放元素
transient Object[] elementData;

懒加载的体现

// 默认初始化容量
private static final int DEFAULT_CAPACITY = 10;

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

transient Object[] elementData;

// 使用无参构造器创建对象,并没有为数组开辟空间,仅仅指定为空数组
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 添加元素
public boolean add(E e) {
    ensureCapacityInternal(size + 1);

    //...
}

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    // 创建集合时,使用的是无参构造器
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        // 第一次添加元素
        // 返回值是DEFAULT_CAPACITY,也就是10
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    // ...
}

// minCapacity是10
private void ensureExplicitCapacity(int minCapacity) {
    // ...

    if (minCapacity - elementData.length > 0)
        // 走扩容的逻辑
        grow(minCapacity);
}

// minCapacity是10
private void grow(int minCapacity) {
    // ...

    // newCapacity = 10
    newCapacity = minCapacity;
    // 创建长度为10的数组
    elementData = Arrays.copyOf(elementData, newCapacity);
}

最大容量为int类型的最大值

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;


private void grow(int minCapacity) {
    // ...

    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    
    // ...
            
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 拿到的newCapacity的值可以是int的最大值
    elementData = Arrays.copyOf(elementData, newCapacity);
}


private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
            // 这里返回了int的最大值
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

扩容机制

private void grow(int minCapacity) {
    // 旧数组容量
    int oldCapacity = elementData.length;
    // 新容量为旧容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 新容量达不到最低容量要求
    if (newCapacity - minCapacity < 0)
        // 新容量赋值为最低要求的容量
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 新数组
    elementData = Arrays.copyOf(elementData, newCapacity);
}

使用equals方法来判断是否包含某个元素

public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            // 使用的是equals方法
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

随机增删元素效率较低,需要移动元素,时间复杂度为O(n)

// 随机增加元素
public void add(int index, E element) {
    // ...

    // 元素移动
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element;
    size++;
}

// 随机删除元素
public E remove (int index){
    // ...

    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        // 元素移动
        System.arraycopy(elementData, index + 1, elementData, index, numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

LinkedList

底层数据结构是双向链表

// 节点
private static class Node {
    // 节点数据值
    E item;
    // next指针,指向下一个节点
    Node next;
    // prev指针,指向上一个节点
    Node prev;
    Node(Node prev, E element, Node next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

add(E e)和remove()方法

// 添加元素
public boolean add(E e) {
    // 从尾部添加
    linkLast(e);
    return true;
}

void linkLast(E e) {
    final LinkedList.Node l = last;
    final LinkedList.Node newNode = new LinkedList.Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

// 删除元素
public E remove() {
    // 从头部删除元素
    return removeFirst();
}

public E removeFirst() {
    final LinkedList.Node f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}

private E unlinkFirst(Node f) {
    final E element = f.item;
    final LinkedList.Node next = f.next;
    f.item = null;
    f.next = null; // help GC
    first = next;
    if (next == null)
        last = null;
    else
        next.prev = null;
    size--;
    modCount++;
    return element;
}

获取元素需要遍历节点,效率较低,时间复杂度为O(n)

// 根据下标获取元素
public E get(int index) {
    //...
            
    return node(index).item;
}

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

随机增删元素效率高,只需要改变指针指向即可,时间复杂度为O(1)

// 随机添加元素
public void add(int index, E element) {
    // ...

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

void linkLast(E e) {
    final Node l = last;
    final Node newNode = new Node<>(l, e, null);
    // 改变指针指向
    last = newNode;
    if (l == null)
        // 改变指针指向
        first = newNode;
    else
        // 改变指针指向
        l.next = newNode;
    size++;
    modCount++;
}

void linkBefore(E e, Node succ) {
    final Node pred = succ.prev;
    final Node newNode = new Node<>(pred, e, succ);
    // 改变指针指向
    succ.prev = newNode;
    if (pred == null)
        // 改变指针指向
        first = newNode;
    else
        // 改变指针指向
        pred.next = newNode;
    size++;
    modCount++;
}

可以用作栈

// 入栈,从链表的头部添加元素
public void push(E e) {
    addFirst(e);
}

// 出栈,从链表的头部删除元素
public E pop() {
    return removeFirst();
}

可以用作队列

// 入队,从链表的尾部添加元素
public boolean offer(E e) {
    return add(e);
}

// 出队,从链表的头部删除元素
public E poll() {
    final Node f = first;
    return (f == null) ? null : unlinkFirst(f);
}

本身就是双向队列

// 实现了Deque接口,两端都可以添加和删除元素
public class LinkedList
    extends AbstractSequentialList
    implements List, Deque, Cloneable, java.io.Serializable



// 头部添加元素
public boolean offerFirst(E e) {
    addFirst(e);
    return true;
}

// 尾部添加元素
public boolean offerLast(E e) {
    addLast(e);
    return true;
}

// 头部删除元素
public E pollFirst() {
    final LinkedList.Node f = first;
    return (f == null) ? null : unlinkFirst(f);
}

// 尾部删除元素
public E pollLast() {
    final LinkedList.Node l = last;
    return (l == null) ? null : unlinkLast(l);
}

你可能感兴趣的:(Java集合框架,list,数据结构)