work hard work smart

专注于Java后端开发。 不断总结,举一反三。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

LinkedList源码解析

Posted on 2020-04-02 18:24  work hard work smart  阅读(128)  评论(0编辑  收藏  举报

1、LinkedList的结构如下

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;

    //第一个节点
    transient Node<E> first;

    //最后一个节点
    transient Node<E> last;

    //节点的结构
    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;
        }
    }

}

  由上面可知,LinkList是一个双向列表结构

 

2、构造函数

    //空的构造函数
    public LinkedList() {
    }

    //传入集合的构造函数
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }  

和ArrayList对比可以发现,LinkedList没有容量的限制,不需要指定集合的大小。

 

3、元素添加

    //1、添加单个元素。在最后一个元素后面添加
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    //2、添加元素到指定位置
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }
    //3、添加到头元素
    public void addFirst(E e) {
        linkFirst(e);
    }
    //4、添加到尾元素
    public void addLast(E e) {
        linkLast(e);
    }
    //5、添加到集合
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

 主要调用了linkFirst和linkLast这两个方法

1) linkLast(E e)

    void linkLast(E e) {
        final Node<E> l = last;
        //1、创建一个Node,prev指向last,netx为空
        final Node<E> newNode = new Node<>(l, e, null);
        //2、last节点为新加的节点
        last = newNode;
        //3、如果last节点为空,则说明新增加的节点newNode是第一个元素。
	//否则,将原来的last节点的next复制为新的节点
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

  

 4、删除操作

删除操作,总结起来就是unlink方法

 E unlink(Node<E> x) {
        //获取当前节点的元素,前一个节点和后一个节点
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
        //如果要删除节点的前一个节点为空,则说明要删除的元素就是第一个元素。
        if (prev == null) {
	    //将该元素的下一个节点赋值给first节点
            first = next;
        } else {
	    //如果要删除节点的前一个节点不为空。则将他前一个节点的next赋值为当前节点的next
            prev.next = next;
            x.prev = null;
        }

	//如果要删除的元素next为空,则说明要删除的元素是最后一个元素。
        if (next == null) {
            //将该元素的前一个节点赋值给last
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
	//将当前元素置为null
        x.item = null;
        size--;
        modCount++;
        return element;
    }

  

 5、修改元素

   public E set(int index, E element) {
        checkElementIndex(index);
	//获取到当前元素
        Node<E> x = node(index);
	//老的元素
        E oldVal = x.item;
	//将新的元素赋值给x.item
        x.item = element;
        return oldVal;
    }

  

6、查询元素

1) 按index查询元素。(查询第几个元素)

    Node<E> node(int index) {
        //如果index在整个链表的前半部分,在从first往后查询
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } 
	//如果index在整个链表的后半部分,在从last往前查询
	else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

 

2) 按照对象查询元素的位置(index) 

    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;
    }

  

 ArrayList和LinkedList使用对比: Java ArrayList,LinkedList使用