LinkedList源码阅读笔记
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源码阅读笔记相关推荐
- LinkedList源码阅读笔记(1.8)
目录 LinkedList类的注解阅读 LinkedList类的定义 属性的定义 LinkedList构造器 核心方法 校验方法 普通方法 迭代器(iterator&ListIterator) ...
- Transformers包tokenizer.encode()方法源码阅读笔记
Transformers包tokenizer.encode()方法源码阅读笔记_天才小呵呵的博客-CSDN博客_tokenizer.encode
- 源码阅读笔记 BiLSTM+CRF做NER任务 流程图
源码阅读笔记 BiLSTM+CRF做NER任务(二) 源码地址:https://github.com/ZhixiuYe/NER-pytorch 本篇正式进入源码的阅读,按照流程顺序,一一解剖. 一.流 ...
- 代码分析:NASM源码阅读笔记
NASM源码阅读笔记 NASM(Netwide Assembler)的使用文档和代码间的注释相当齐全,这给阅读源码 提供了很大的方便.按作者的说法,这是一个模块化的,可重用的x86汇编器, 而且能够被 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http:// ...
- Yii源码阅读笔记 - 日志组件
2015-03-09 一 By youngsterxyf 使用 Yii框架为开发者提供两个静态方法进行日志记录: Yii::log($message, $level, $category); Yii: ...
- AQS源码阅读笔记(一)
AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node {//表示当前节点以共享模式等待锁static final Node SHA ...
- 【Flink】Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型
1.概述 转载:Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型 相似文章:[Flink]Flink 基于 MailBox 实现的 StreamTask 线程模型 Fl ...
- 【Flink】Flink 源码阅读笔记(18)- Flink SQL 中的流和动态表
1.概述 转载:Flink 源码阅读笔记(18)- Flink SQL 中的流和动态表
最新文章
- MySQL安装最后一步apply security settings错误
- CentOS7下安装GUI图形界面
- [经典推荐]事半功倍系列之javascript
- JavaFX技巧7:使用CSS颜色常量/派生颜色
- uboot主Makefile之9——2589行 x210_sd_config目标
- 墨天轮社区专属福利:与作者互动问答,民工哥全新力作《Linux系统运维指南:从入门到企业实战》送上!...
- pythongetattribute_Python __getattribute__ vs __getattr__ 浅谈
- idea 按空格不会换行_原机输入法第三方App如何 “换行”
- 分享12306全自动验证码识别提交,春运抢票准备时
- IP地址的分类,五分类编制CIDR以及子网的划分和子网掩码
- TimesTen In-Memory Database
- 微信公众号推送的模板消息无法跳转到小程序指定页面?
- 写一个AndroidStudio有道翻译插件给大家
- 佳能打印机 出现5100错误怎么办
- 闲鱼如何高效打造一个多业务、低侵入的搜索链路
- 混jdon坛子的一些思考
- PTA L1-003 个位数统计(详解)
- 【HighChart教程】编程语言详细程度的互动比较
- 5分钟搭建大数据学习环境
- 2019日本Summer Sonic音乐节攻略(明星阵容)