LinkedList add get 源码解析
Posted zhangxuezhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LinkedList add get 源码解析相关的知识,希望对你有一定的参考价值。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
其中Deque为双端队列
add(E e)方法如下,就是在链表的最后一项,在其next项附上要添加的数据
/** * Appends the specified element to the end of this list. * * <p>This method is equivalent to {@link #addLast}. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { linkLast(e); return true; } /** * Links e as last element. */ void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) //如果last节点为空,说明链表是空的,那么新增的数据既是first又是last first = newNode; else //如果last不为空,把新增的元素链接到原来的last的next l.next = newNode; size++; modCount++; } 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; } }
add(int index, E e)方法如下,就是在指定位置,把新节点插入到链表,并对应更新其前驱和后续节点的链接关系。
/** * Inserts the specified element at the specified position in this list. * Shifts the element currently at that position (if any) and any * subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { //检查索引是否越界 checkPositionIndex(index); if (index == size) //在链表末端添加新节点 linkLast(element); else //在指定位置插入新节点 linkBefore(element, node(index)); } private void checkPositionIndex(int index) { if (!isPositionIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * Tells if the argument is the index of a valid position for an * iterator or an add operation. */ private boolean isPositionIndex(int index) { return index >= 0 && index <= size; } /** * Inserts element e before non-null Node succ. */ void linkBefore(E e, Node<E> succ) { // assert succ != null; //保留要插入节点位置的前驱节点 final Node<E> pred = succ.prev; //新建节点 final Node<E> newNode = new Node<>(pred, e, succ); //把新建节点作为原节点的前驱节点 succ.prev = newNode; //把新建节点作为pred的后续节点,或者作为链表头结点 if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
get方法如下:
/** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { //检查索引是否越界 checkElementIndex(index); //根据索引,遍历链表找到数据 return node(index).item; } private void checkElementIndex(int index) { if (!isElementIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * Tells if the argument is the index of an existing element. */ private boolean isElementIndex(int index) { return index >= 0 && index < size; } /** * Returns the (non-null) Node at the specified element index. */ 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; } }
根据索引获取元素时,有个小技巧,就是把链表对半分,当索引在前半段时,从前往后遍历,否则反向遍历,该算法可以节省遍历次数,从一半,减为四分之一。
有个需要注意的地方,Linkedlist里面有两个很相似的方法,一个是获取数据时,检查索引下标是否越界;另外一个是添加数据时,添加位置索引小标是否越界。前者边界条件比后者小1,代码如下:
/** * Tells if the argument is the index of an existing element. */ private boolean isElementIndex(int index) { return index >= 0 && index < size; } /** * Tells if the argument is the index of a valid position for an * iterator or an add operation. */ private boolean isPositionIndex(int index) { return index >= 0 && index <= size; }
remove(Object o)函数,该函数从前往后遍历链表,删除第一个满足条件的数据,到此结束。
/** * Removes the first occurrence of the specified element from this list, * if it is present. If this list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index * {@code i} such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> * (if such an element exists). Returns {@code true} if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). * * @param o element to be removed from this list, if present * @return {@code true} if this list contained the specified element */ public boolean remove(Object o) { 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; } /** * Unlinks non-null node x. */ E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; //前驱节点解绑,如果前驱节点为空,则后续节点成为first if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } //后续节点解绑,如果后续节点为空,则前驱节点成为last if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } //节点数值释放,方便gc回收 x.item = null; size--; modCount++; return element; }
remove(int index)方法,先检查索引是否越界,然后根据索引获取node,调用unlink方法解绑该节点。
/** * Removes the element at the specified position in this list. Shifts any * subsequent elements to the left (subtracts one from their indices). * Returns the element that was removed from the list. * * @param index the index of the element to be removed * @return the element previously at the specified position * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { checkElementIndex(index); return unlink(node(index)); }
以上是关于LinkedList add get 源码解析的主要内容,如果未能解决你的问题,请参考以下文章