LinkedList源码阅读笔记

初始化

  • 无参的
public LinkedList() {}
  • 初始化的同时添加一个Collection
public LinkedList(Collection<? extends E> c) {this();addAll(c);}
  • addAll(c)方法待会在add的时候会讲。

成员变量们

transient int size = 0;
transient Node<E> first;
transient Node<E> last;

Node类

他是LinkedList的内部private类。

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,addAll,addFirst,addLast

add(E e)

public boolean add(E e) {linkLast(e);return true;}

直接默认添加在link尾部。

  • linkLast(E e)
    /*** Links e as last element.*/void linkLast(E e) {final Node<E> l = last;//final域指向last节点final Node<E> newNode = new Node<>(l, e, null);//构造新节点作为最后一个节点,next = nulllast = newNode;//设置新节点为最后一个节点if (l == null)//如果这是一个空链表(null==first==last)first = newNode;else//不是空链表,让原last的next指针指向新节点l.next = newNode;size++;modCount++;//增加list结构改变次数,用于规避并发产生的错误}

add(int index, E element)

根据索引添加,跟ArrayList差不多,index从0开始。

public void add(int index, E element) {checkPositionIndex(index);if (index == size)linkLast(element);elselinkBefore(element, node(index));}
  • 首先调用checkPositionIndex检查是否越界。
private void checkPositionIndex(int index) {if (!isPositionIndex(index))throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}private boolean isPositionIndex(int index) {return index >= 0 && index <= size;}

就是很平常的跟size和0比较。但是请注意,index是可以 == size的。

  • 然后如果index == size ,表示我想在最后一个元素的后面添加e。那就直接调用刚刚的linkLast就可以了。
  • 如果不是就需要调用node(index)和void linkBefore(E e, Node succ) {}了。

    • node(int index)
    /*** 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;}
    }

    通过双向节点的好处和分为两段遍历减少遍历量提高性能。注意这个地方用不成二分法(二分法需要数组的下标来和查询的index比较)。

    如果是前半段就从0往后遍历,直到index,返回即可。

    如果是后半段就从后往前遍历,直到index,返回即可。

    • linkBefore(E e, Node succ)
    /*** 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;if (pred == null)first = newNode;elsepred.next = newNode;size++;modCount++;
    }
    • 需要四步:pred.next = newNode;nowNode.prev=pred;newNode.next=succ;succ.prev=newNode;
    • 其中关于设置newNode的前后指针的在new Node<>(pred,e,succ);完成。

批量增加 boolean addAll(Collection

    /*** Appends all of the elements in the specified collection to the end of* this list, in the order that they are returned by the specified* collection's iterator.  The behavior of this operation is undefined if* the specified collection is modified while the operation is in* progress.  (Note that this will occur if the specified collection is* this list, and it's nonempty.)** @param c collection containing elements to be added to this list* @return {@code true} if this list changed as a result of the call* @throws NullPointerException if the specified collection is null*/public boolean addAll(Collection<? extends E> c) {return addAll(size, c);}

批量增加 boolean addAll(int index, Collection

    /*** Inserts all of the elements in the specified collection into this* list, starting at the specified position.  Shifts the element* currently at that position (if any) and any subsequent elements to* the right (increases their indices).  The new elements will appear* in the list in the order that they are returned by the* specified collection's iterator.** @param index index at which to insert the first element*              from the specified collection* @param c collection containing elements to be added to this list* @return {@code true} if this list changed as a result of the call* @throws IndexOutOfBoundsException {@inheritDoc}* @throws NullPointerException if the specified collection is null*/public boolean addAll(int index, Collection<? extends E> c) {checkPositionIndex(index);Object[] a = c.toArray();int numNew = a.length;if (numNew == 0)return false;Node<E> pred, succ;if (index == size) {succ = null;pred = last;} else {succ = node(index);pred = succ.prev;}for (Object o : a) {@SuppressWarnings("unchecked") E e = (E) o;//J2SE 提供的最后一个批注是 @SuppressWarnings。该批注的作用是给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默。 Node<E> newNode = new Node<>(pred, e, null);if (pred == null)first = newNode;elsepred.next = newNode;pred = newNode;}if (succ == null) {last = pred;} else {pred.next = succ;succ.prev = pred;}size += numNew;modCount++;return true;}
  • 总体思路就是检查越界,被插入节点succ,被插入节点的上一个节点pred,注意要考虑到在link尾部插入的情况(当index==size就没有succ了),然后遍历c.toArray(),让一个个数据链接到pred.next(注意要考虑到在空link中插入collection),遍历完成后把succ和最新的pred链接起来。

删除

返回并删除第一个元素poll()

public E poll() {final Node<E> f = first;return (f == null) ? null : unlinkFirst(f);}
  • unlinkFirst(f)
    /*** Unlinks non-null first node f.*/private E unlinkFirst(Node<E> f) {// assert f == first && f != null;final E element = f.item;final Node<E> next = f.next;f.item = null;f.next = null; // help GCfirst = next;if (next == null)last = null;elsenext.prev = null;size--;modCount++;return element;}

从此列表所表示的堆栈处弹出一个元素pop()

    /*** Pops an element from the stack represented by this list.  In other* words, removes and returns the first element of this list.** <p>This method is equivalent to {@link #removeFirst()}.** @return the element at the front of this list (which is the top*         of the stack represented by this list)* @throws NoSuchElementException if this list is empty* @since 1.6*/public E pop() {return removeFirst();}

返回并删除第一个元素
- removeFirst():

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

remove == removeFirst

删除第一个出现的元素removeFirstOccurrence(Object o) == remove(Object o)

  • remove(Object o)
    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;}

可以看出LinkedList是支持元素为空的。

为null和非null分开unlink()
- unlink(Node node)

    /*** 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;if (prev == null) {first = next;} else {prev.next = next;x.prev = null;}if (next == null) {last = prev;} else {next.prev = prev;x.next = null;}x.item = null;size--;modCount++;return element;}

移除最后一次出现的指定元素(从头部到尾部遍历列表时)removeLastOccurrence

    public boolean removeLastOccurrence(Object o) {if (o == null) {for (Node<E> x = last; x != null; x = x.prev) {if (x.item == null) {unlink(x);return true;}}} else {for (Node<E> x = last; x != null; x = x.prev) {if (o.equals(x.item)) {unlink(x);return true;}}}return false;}

因为有prev指针的存在,所以跟removeFirstOccurrence差不多。

修改 set(int index, E element)

    public E set(int index, E element) {checkElementIndex(index);Node<E> x = node(index);E oldVal = x.item;x.item = element;return oldVal;}

检查越界,通过node(int index)找到该节点,修改该节点。

查询 get

    public E get(int index) {checkElementIndex(index);return node(index).item;}

emmmmmmm 还是node(int index)

LinkedList源码阅读笔记相关推荐

  1. LinkedList源码阅读笔记(1.8)

    目录 LinkedList类的注解阅读 LinkedList类的定义 属性的定义 LinkedList构造器 核心方法 校验方法 普通方法 迭代器(iterator&ListIterator) ...

  2. Transformers包tokenizer.encode()方法源码阅读笔记

    Transformers包tokenizer.encode()方法源码阅读笔记_天才小呵呵的博客-CSDN博客_tokenizer.encode

  3. 源码阅读笔记 BiLSTM+CRF做NER任务 流程图

    源码阅读笔记 BiLSTM+CRF做NER任务(二) 源码地址:https://github.com/ZhixiuYe/NER-pytorch 本篇正式进入源码的阅读,按照流程顺序,一一解剖. 一.流 ...

  4. 代码分析:NASM源码阅读笔记

    NASM源码阅读笔记 NASM(Netwide Assembler)的使用文档和代码间的注释相当齐全,这给阅读源码 提供了很大的方便.按作者的说法,这是一个模块化的,可重用的x86汇编器, 而且能够被 ...

  5. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http:// ...

  6. Yii源码阅读笔记 - 日志组件

    2015-03-09 一 By youngsterxyf 使用 Yii框架为开发者提供两个静态方法进行日志记录: Yii::log($message, $level, $category); Yii: ...

  7. AQS源码阅读笔记(一)

    AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node {//表示当前节点以共享模式等待锁static final Node SHA ...

  8. 【Flink】Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型

    1.概述 转载:Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型 相似文章:[Flink]Flink 基于 MailBox 实现的 StreamTask 线程模型 Fl ...

  9. 【Flink】Flink 源码阅读笔记(18)- Flink SQL 中的流和动态表

    1.概述 转载:Flink 源码阅读笔记(18)- Flink SQL 中的流和动态表

最新文章

  1. MySQL安装最后一步apply security settings错误
  2. CentOS7下安装GUI图形界面
  3. [经典推荐]事半功倍系列之javascript
  4. JavaFX技巧7:使用CSS颜色常量/派生颜色
  5. uboot主Makefile之9——2589行 x210_sd_config目标
  6. 墨天轮社区专属福利:与作者互动问答,民工哥全新力作《Linux系统运维指南:从入门到企业实战》送上!...
  7. pythongetattribute_Python __getattribute__ vs __getattr__ 浅谈
  8. idea 按空格不会换行_原机输入法第三方App如何 “换行”
  9. 分享12306全自动验证码识别提交,春运抢票准备时
  10. IP地址的分类,五分类编制CIDR以及子网的划分和子网掩码
  11. TimesTen In-Memory Database
  12. 微信公众号推送的模板消息无法跳转到小程序指定页面?
  13. 写一个AndroidStudio有道翻译插件给大家
  14. 佳能打印机 出现5100错误怎么办
  15. 闲鱼如何高效打造一个多业务、低侵入的搜索链路
  16. 混jdon坛子的一些思考
  17. PTA L1-003 个位数统计(详解)
  18. 【HighChart教程】编程语言详细程度的互动比较
  19. 5分钟搭建大数据学习环境
  20. 2019日本Summer Sonic音乐节攻略(明星阵容)

热门文章

  1. 微软发布Mac 8版Messenger 支持视频会议(图)
  2. 手写楚列斯基分解(楚列斯基因子分解) Matlab代码
  3. 为什么 UDP 有时比 TCP 更有优势
  4. Trans论文的发表流程(George E.Ponchak)
  5. 验证手机号是否注册过爱奇艺
  6. mysql5.7.23绿色版安装
  7. 【go-jira】go根据jql获取jira数据,包括total及bug的平均未解决时间
  8. 敏捷开发 SOLID 原则
  9. 自选项目--手机锁屏软件--NABC分析
  10. 2019年回头看,英特尔要如何突破存储瓶颈?