Java LinkedList 源码阅读笔记

LinkedList 源码阅读

指针
//链表指针对象
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;
    }
}
成员边变量
LinkedList 的 长度. size(); 返回的就是这个数值.
transient int size = 0;

/**
 * Returns the number of elements in this list.
 *
 * @return the number of elements in this list
 */
 public int size() {
   return size;
 }
LinkedList 的头部指针 和 尾部指针.
  /**
     * Pointer to first node. Invariant: (first == null && last == null) || (first.prev == null && first.item != null)
     */
    // 指向第一个节点的指针
    // 链表 头部 指针
    transient Node<E> first;

    /**
     * Pointer to last node. Invariant: (first == null && last == null) || (last.next == null && last.item != null)
     */
    // 指向最后一个节点的指针
    // 链表 尾部 指针
    transient Node<E> last;
构造函数
默认无参构造函数
    /**
     * Constructs an empty list. 默认构造函数
     */
    public LinkedList() {}
带初始化集合的构造函数
public LinkedList(Collection<? extends E> c) {
    // 调用无参构造函数
    this();
    // 将初始化集合 添加到链表
    addAll(c);
}

public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
}

public boolean addAll(int index, Collection<? extends E> c) {
    // 校验 索引下标是否合法.
    // 上一层函数传入的参数 为链表的长度,此处合法跳过.
    checkPositionIndex(index);
	
	// 将初始化集合转为 Object 数组
    Object[] a = c.toArray();
    // 获取数组的长度
    int numNew = a.length;
	// 如果
    if (numNew == 0)
        // 结束函数.
        return false;
    // pred (上一个指针)
    // succ 索引位置的指针    
    Node<E> pred, succ;
        // 如果 索引位置 等于 集合长度
        if (index == size) {
        	// 索引位置的指针 为 null
            succ = null;
            // 上一个指针便是 链表之前的 尾部指针.
            pred = last;
        } else {
        	// 获取 索引位置的指针. 下文有函数注释,
            succ = node(index); 
            // 上一个指针 便是 索引位置指针的 上一个指针.
            pred = succ.prev;
        }
		
		// 遍历 Object 数组
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            // 创建新的指针, 
            // 新指针的上一个指针 未 pred.
            Node<E> newNode = new Node<>(pred, e, null);
            // 如果新指针的 上一个指针 为 null
            if (pred == null)
            	// 将新指针设置为 头部指针
                first = newNode;
            else
                // 否则 将新指针设置为 pred 的 下一个指针.
                pred.next = newNode;
            // 将下一个指针变成 新创建的指针, 再次进行循环,
            pred = newNode;
        }
		// 此时 pred 已经是 Object 的最后一个元素生成的指针了.
		// 如果 目标索引位置的 指针 为 空,(从链表尾部开始追加)
        if (succ == null) {
        	// 将 pred 设置 为上一个 指针.
            last = pred;
        } else {
        	//从某个索引位置开始追加.
        	//将 Object 最后一个元素生成的指针的 下一个指针设置未 索引位置的指针.
            pred.next = succ;
            // 将索引位置指针的上一个指针 设置为 Object 最后一个元素生成的指针
            succ.prev = pred;
        }
		
		// 链表的长度 增加 Object数组的长度.
        size += numNew;
        // 链操作数 +
        modCount++;
        // 函数返回结束
        return true;
    }

// 返回 index 位置的链表指针.
Node<E> node(int index) {
   // assert isElementIndex(index);
   // size >> 1 等同于0.5(size)
   // 由于链表和数组的结构不同,无法直接通过索引获取值.
   // 链表只能通过遍历,依次获取值.
   // 这里 size 取半是为了 避免全链表遍历.
   // 根据 size 取半的值可以判断出 index 距离 头部近还是 尾部近.
   if (index < (size >> 1)) {
   	   // 距离头部近,从头部开始遍历,到index的所在位置结束,然后 x位置在的值. 
       Node<E> x = first;
       for (int i = 0; i < index; i++)
           x = x.next;
      return x;
   } else {
  	   // 距离尾部近,从头部开始遍历,到index的所在位置结束,然后 x位置在的值. 
       Node<E> x = last;
       for (int i = size - 1; i > index; i--)
           x = x.prev;
       return x;
   }
}

// 校验函数
private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
	    // 不合法 抛出异常.
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 索引值必须大于 等于 0 且 索引值小于等于 链表长度.
private boolean isPositionIndex(int index) {
    return index >= 0 && index <= size;
}
新增元素
add (E e) 新增元素
public boolean add(E e) {
    // 默认add 函数会往链表末端追加元素.
    linkLast(e);
    return true;
}
linkLast(E e) 追加到链表尾部
void linkLast(E e) {
	// 将当前链表末端指针复制给变量 l
    final Node<E> l = last;
    // 创建新的指针, 指针的存储 e ,指针的上一个指针设置为 l
    final Node<E> newNode = new Node<>(l, e, null);
    // 新的指针设置为 末端指针.
    last = newNode;
    // 原先的末端指针未空,
    if (l == null)
    	// 将新的指针设置为链表头部指针.
        first = newNode;
    else
    	// 将末端指针(旧)的next节点引用设置未 新节点.
        l.next = newNode;
    // 集合的长度 + 1    
    size++;
    // 链操作数 + 1 
    modCount++;
}
add (int index, E element) 给指定索引添加元素
public void add(int index, E element) {
	// 校验 索引合法性.
	// 索引值必须大于 等于 0 且 索引值小于等于 链表长度.
    checkPositionIndex(index);
    
    // 如果 索引值等于 链表的长度.
    if (index == size)
    	// 追加到链表尾部(见上文)
        linkLast(element);
    else
    	// 追加到指定索引位置.
    	// node(index) ,返回index位置的链表指针.
        linkBefore(element, node(index));
}

// 返回 index 位置的链表指针.
Node<E> node(int index) {
   // assert isElementIndex(index);
   // size >> 1 等同于0.5(size)
   // 由于链表和数组的结构不同,无法直接通过索引获取值.
   // 链表只能通过遍历,依次获取值.
   // 这里 size 取半是为了 避免全链表遍历.
   // 根据 size 取半的值可以判断出 index 距离 头部近还是 尾部近.
   if (index < (size >> 1)) {
   	   // 距离头部近,从头部开始遍历,到index的所在位置结束,然后 x位置在的值. 
       Node<E> x = first;
       for (int i = 0; i < index; i++)
           x = x.next;
      return x;
   } else {
  	   // 距离尾部近,从头部开始遍历,到index的所在位置结束,然后 x位置在的值. 
       Node<E> x = last;
       for (int i = size - 1; i > index; i--)
           x = x.prev;
       return x;
   }
}

// 校验函数
private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
	    // 不合法 抛出异常.
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 索引值必须大于 等于 0 且 索引值小于等于 链表长度.
private boolean isPositionIndex(int index) {
    return index >= 0 && index <= size;
}
linkBefore(E e, Node succ)
E e 添加的元素.
Node<E> succ 索引位置的 指针,
void linkBefore(E e, Node<E> succ) {
    // assert succ != null;
    // 获取索引位置指针的 上一个指针.
    final Node<E> pred = succ.prev;
    // 创建新指针, 新指针将 pred 设置为他的 上一个指针,将 succ 设置为他的下一个指针,
    final Node<E> newNode = new Node<>(pred, e, succ);
    // 将原先索引位置指针的 上一个指针设置为 新创建的指针.
    succ.prev = newNode;
    // 如果新节点的上一个指针是空的.
    if (pred == null)
    	// 将新节点设置未 头部指针
        first = newNode;
    else
    	// 否则 将 pred 的 下一个指针设置为 新创建的指针
        pred.next = newNode;
    // 集合长度 + 1    
    size++;
    // 链操作数 + 1
    modCount++;
}
删除元素
E remove(int index) 异常指定索引的元素.
public E remove(int index) {
	// 校验索引是否越界
    checkElementIndex(index);
    // node(index) 上文已经看过了.  返回索引位置的指针
    return unlink(node(index));
}

private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 这里的索引范围 : 从 0 开始到集合总长度, 但不包括size
private boolean isElementIndex(int index) {
    return index >= 0 && index < size;
}
E unlink(Node x) 将某个元素从链上剔除
E unlink(Node<E> x) {
    // assert x != null;
    // 取出 指针中的 元素
    final E element = x.item;
    // 获取 x 的下一个指针.
    final Node<E> next = x.next;
    // 获取 x 的上一个指针
    final Node<E> prev = x.prev;
    
    // 如果上一个指针 为 null
    if (prev == null) {
        // next 指针就是头部指针了
        first = next;
    } else {
        // 否则 prev 的 next 指针 就由 x -> next
        prev.next = next;
        // x 指针的头部引用 断开.
        x.prev = null;
    }
	
	// 如何 x 的next 节点是 null.
    if (next == null) {
    	// 那么 x 的 prev 指针 就是 新的 尾部指针了.
        last = prev;
    } else {
        // 否则 x的 next 指针的 prev 指针 就是 prev 指针
        next.prev = prev;
        // 将x 指针的尾部引用 断开
        x.next = null;
    }

    // 将 x 指针位置的 元素设置为 null
    x.item = null;
    // 链表的长度 -1
    size--;
    // 链操作数 + 1
    modCount++;
    return element;
}

boolean remove(Object o) 从链表上移除某个元素.
public boolean remove(Object o) {
	//  如果 移除的 元素 是 null.
    if (o == null) {
    	// 遍历全链表 找到 null 然后移除.
    	for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
            	// unlink 见上文
                unlink(x);
                return true;
            }
        }
    } else {
    	// 移除元素不是null/
    	// 遍历全链表 找到 o 然后移除.
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                // unlink 见上文
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

总结
1.LinkedList 底层是 使用 链表结构存储.
2.新增元素是,只需改变 指针 头尾部 的 指针引用.然后插入元素后,再重新更改指针引用即可.
2.1 :不同于ArrayList 由于链表和数组 结构的不同,不需要进行扩容校验,不需要进行,预先分配内存,也不需要连续的,顺序的内存空间.
3.根据索引值 删除元素时, 可以依据索引值的大小, 选择性的从头部 或者尾部 开始遍历链接,极大程度上避免了全链遍历.
4.直接根据 元素 删除元素时, 则需要全链遍历.然后删除.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值