LinkedList源码分析

一、创建一个 LinkedList 的对象
LinkedList list = new LinkedList();

当实例化 LinkedList 时,构造器什么也没做。

public LinkedList() {
}
二、添加一个元素
LinkedList list = new LinkedList();
... // 可能添加很多个元素了
list.add(new Object());

看一下源码

public boolean add(E e) {
	// 把元素追加到链表的后面
    linkLast(e);
    return true;
}

分析这个 linkLast(),看看它里面做了什么

void linkLast(E e) {
	// 把最后一个元素的地址赋给 l
    final Node<E> l = last;
    /*
    根据你要添加的这个元素创建一个新的节点,此时这个元素就应该是最后一个元素,所以它的前一个节点
    应该是之前的最后一个元素,也就是 l。因为它是最后一个元素,所以它后面就没有节点了,也就是 null。(Node 类在下面)
     */
    final Node<E> newNode = new Node<>(l, e, null);
    // 把这个新的节点作为最后一个元素
    // 注意:此时这个节点还没有被加入到数组中
    last = newNode;
    if (l == null)
    	// 如果 l 为 null,也就是说之前这个链表中并没有元素(first = last = null),
    	// 所以这个新节点既是最后一个元素也是第一个元素
        first = newNode;
    else
    	// 把这个节点放在链表中,作为之前最后一个元素的下一个元素
        l.next = newNode;
    size++; // 元素个数 + 1
    modCount++; // 修改次数 + 1
}

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;
    }
}
三、移除一个元素
ArrayList list = new ArrayList();
... // 可能添加很多个元素了
list.add(new Object());
list.remove(int index);

快乐源码,gogogo!

public E remove(int index) {
	// 检查这个元素的索引是不是有效的
    checkElementIndex(index);
    return unlink(node(index));
}

private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private boolean isElementIndex(int index) {
	// 判断这个 index 索引是不是在有效的范围内
    return index >= 0 && index < size;
}

接下来分析这个 unlink(),在分析它之前,我们先分析一下这个 unlink() 里面的 node()

// 返回指定索引处的节点
Node<E> node(int 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;
    }
}

接下来该到 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) {
    	// 如果要移除的元素是第一个元素,就把 next 作为第一个元素
        first = next;
    } else {
    	// 如果不是第一个元素,就把前一个元素的 next 指向它的 next
        prev.next = next;
        x.prev = null; // help GC
    }

    if (next == null) {
    	// 如果是最后一个元素,就把 prev 作为最后一个元素
        last = prev;
    } else {
    	// 如果不是最后一个元素,就把后一个元素的 prev 指向它的前一个元素
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--; // 元素个数 - 1
    modCount++; // 修改次数 + 1
    return element;
}

痛快吧,over 了

四、插入一个元素

源码走起

public void add(int index, E element) {
	// 检查这个索引是否有效,无效则抛出异常,checkPositionIndex() 代码在下面
    checkPositionIndex(index);
	
    if (index == size)
    	// 如果你要插入到最后,那我就直接给你追加到最后得了
		// linkLast() 就是之前 add() 所调用的那个方法
        linkLast(element);
    else
    	//  node(index):获取 index 索引处的节点,在 remove() 那里我们刚刚见过
        linkBefore(element, node(index));
}

看一下这个 checkPositionIndex(),我都不想看了,里面逻辑和之前那个差不多的

private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private boolean isPositionIndex(int index) {
	// 注意:这里是 index <= size,因为可以插入在最后嘛,对吧
    return index >= 0 && index <= size;
}

接下来分析 linkBefore() 这个方法,里面做的事情也很简单

void linkBefore(E e, Node<E> succ) {
	// succ 就是之前 index 索引处的那个节点,别换个名字就不认识了
	// 获取 succ 的前一个节点
    final Node<E> pred = succ.prev;
    /* 
    根据当前要插入的这个元素创建一个新节点,因为要插入在 succ 的前面嘛,
    所以它的前一个节点就是 succ 的前一个节点,它的后一个节点就是 succ
     */
    final Node<E> newNode = new Node<>(pred, e, succ);
    
    // succ 的前一个节点自然而然的就是这个新节点呗
    succ.prev = newNode;
    if (pred == null)
    	// 如果要插入的位置是 index 为 0 的位置,也就是第一个元素,那就把这个新节点作为第一个元素
        first = newNode;
    else
    	// 如果不是 index 为 0 的位置,那 succ 前面的那个节点的后一个节点就是这个新的节点
        pred.next = newNode;
    size++; // 元素个数 + 1
    modCount++; // 修改次数 + 1
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值