当前位置:网站首页>LinkedList源码按摩,啊舒服
LinkedList源码按摩,啊舒服
2022-07-28 09:46:00 【醉鱼!】
首先看一下LinkedList的声明
public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable{}
AbstractSequentialList 分析
官方文档的解释如下
This class provides a skeletal implementation of the <tt>List</tt>interface to minimize the effort required to implement this interfacebacked by a "sequential access" data store (such as a linked list). Forrandom access data (such as an array), <tt>AbstractList</tt> should be usedin preference to this class.<p>
意思大概就是对于随机访问的数据或者数组,应优先使用AbstractSequentialList,即
E get(int index)E set(int index, E element)void add(int index, E element)E remove(int index)boolean addAll(int index, Collection<? extends E> c)
上面的这几个接口都是随机访问的
实现List<E>可以有list的特性
实现Deque,可以使用双端队列访问元素的方法,是一个双向链表
实现Cloneable,可以实现克隆对象的全部元素
实现java.io.Serializable,可以实现序列化
常量
// 元素个数transient int size = 0;// 指向头指针transient Node<E> first;// 指向末尾指针transient Node<E> last;
构造方法
// 无参构造方法,生成空的链表public LinkedList() {}// 构建一个包含指定元素集合的列表,顺序有Collection的iterator返回public LinkedList(Collection<? extends E> c) {this();addAll(c);}
节点结构
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;}}
头节点插入
/*** 头节点插入元素e* 先拿到当前头结点定义为f,定一个新的节点newNode,pre指向null,元素为e,next指向f* 在修改新的头节点为newNode* 判断拿到的头节点f是否为空,如果为空last为newNode,此时链表就一个元素newNode* 如果不为空,f的pre节点指向newNode新创建的节点* size ++* modCount 涉及修改数据结构都要修改的值,即修改统计数,用来实现fail-fast机制*/private void linkFirst(E e) {final Node<E> f = first;final Node<E> newNode = new Node<>(null, e, f);first = newNode;if (f == null)last = newNode;elsef.prev = newNode;size++;modCount++;}
末尾节点添加元素
/*** 末尾节点添加元素e* 获取当前尾部节点last为l* 定义新节点newNode,pre为l,元素为e,next为null* 定义现在last尾部节点为newNode* 如果刚才首次获取尾部节点l为null,头部节点改为newNode,此时链表就y一个元素* 如果不为null,l的next节点就为我们的newNode* 元素个数添加* 修改次数添加,和上面类似*/void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++;}
在非null元素succ之前插入元素
/*** 在非null元素succ之前插入元素e* 拿到succ的pre节点pred* 创建newNode节点保存我们要插入的数据,pre为刚才取得pred节点,元素为e,next为succ* 修改succ的pre节点为创建的newNode节点* 判断如果pred拿出的为null,即pred就是头节点,first为newNode* 不为null,pred的next节点为新创建的newNode* 修改元素个数size* 修改次数添加*/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++;}
取消链接非空的第一个节点
/*** 取消第一个节点f的链接* 取出f节点元素element* 取出f的后置节点next* 然后把f的元素值置为null,next置为null,置为nullgc更快回收* 链表的头节点定义为刚才取出的后置节点next* 判断next节点是否为空,如果为null,last也为null,链表为k空* 不为null next的前置节点置为null* 元素个数减少1* 修改次数添加*/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;}
取消链接的最后一个节点
/*** 取消链接的最后一个非k空节点l* 取出l节点的元素element* 取出l节点的前置节点prev* l元素置为null,pre前置节点置为null* 链表的last置为f节点的pre节点prev* 判断如果pre节点为null,链表first头节点为null* 不为null,prev的后置节点置为null断开元素的链接* 元素个数减少1* 修改次数添加*/private E unlinkLast(Node<E> l) {// assert l == last && l != null;final E element = l.item;final Node<E> prev = l.prev;l.item = null;l.prev = null; // help GClast = prev;if (prev == null)first = null;elseprev.next = null;size--;modCount++;return element;}
取消链接非空节点
/*** 取消链接非空节点x* 分别取到x节点的元素值element,前置节点prev,后置节点next* 如果元素x的前置节点为null,链表的first 指向next节点,如果不为null,prev节点的next执行元素x的next节点* 如果元素x的后置节点为null,链表的last节点为x的prev前置节点,不为null,元素x后置节点的pre指向x的前置节点* x元素值置为null* 元素减少1* 修改次数添加*/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;}
获取链表的第一个元素
/*** 拿到first指向的元素* 判断是否为null,为null抛出NoSuchElementException()list为空异常* 不为null,返回f.item的元素本身*/public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;}
获取链表的最后一个元素
/*** 根据last拿到链表的最后一个元素值* 判断last是否为null,如果为null,返回list为空的异常* 不为null,返回l.item元素本身*/public E getLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return l.item;}
删除链表中第一个元素并返回
/*** 拿到first第一个元素* 如果为null,抛出list为empty的异常* 不为null调用unlinkFirst(f)方法来取消元素的链接*/public E removeFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return unlinkFirst(f);}
删除链表中最后一个元素并返回
/*** 根据last获取链表的最后一个元素* 如果为null,抛出list为empty的异常* 不为null调用unlinkLast(l)方法,取消最后一个元素的链接*/public E removeLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return unlinkLast(l);}
指定元素添加到链表头部
/*** 直接调用linkFirst(e)方法添加*/public void addFirst(E e) {linkFirst(e);}
指定元素添加到链表尾部
/*** 调用linkLast(e)方法尾部添加元素e*/public void addLast(E e) {linkLast(e);}
判断链表中是否包含元素
/*** 判断链表是否包含元素o* 调用indexOf(o)方法,indexOf方法见下面解析,返回元素的索引,找不到或者索引不存在返回-1*/public boolean contains(Object o) {return indexOf(o) != -1;}
indexOf(Object o)
/*** 返回元素o在此链表中 【首次】出现的位置* 如果list不包含元素o,返回-1* 更正式的说,返回元素的索引,如果索引值不存在返回-1*/public int indexOf(Object o) {int index = 0;if (o == null) {for (Node<E> x = first; x != null; x = x.next) {if (x.item == null)return index;index++;}} else {for (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item))return index;index++;}}return -1;}
获取list元素个数
public int size() {return size;}
添加一个元素
/*** 添加一个元素e* 调用linkLast(e)在队列的尾部添加元素* 返回true*/public boolean add(E e) {linkLast(e);return true;}
删除一个元素
/*** 如果元素o存在的话,移除首次出现的元素,即最小索引的元素,* 如果元素o为null,移除首次出现的null元素* 如果元素o不在list中,不做任何改变* 如果元素o匹配上,调用unlink(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;}
addAll 方法添加指定的集合元素
public boolean addAll(Collection<? extends E> c) {// 从什么位置开始添加,此处从原list的末尾开始添加元素集合creturn addAll(size, c);}/*** index: 开始添加元素的位置* c: 要添加的元素集合*/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;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;}
清空list,删除所有的元素
public void clear() {// Clearing all of the links between nodes is "unnecessary", but:// - helps a generational GC if the discarded nodes inhabit// more than one generation// - is sure to free memory even if there is a reachable Iteratorfor (Node<E> x = first; x != null; ) {Node<E> next = x.next;x.item = null;x.next = null;x.prev = null;x = next;}first = last = null;size = 0;modCount++;}
get(index)
/*** 返回指定位置的元素* 检测index索引是否有效* 返回index索引位置元素*/public E get(int index) {checkElementIndex(index);return node(index).item;}
指定位置覆盖原先位置元素
/*** 检验index是否有效* 获取index位置节点* 替换node节点item*/public E set(int index, E element) {checkElementIndex(index);Node<E> x = node(index);E oldVal = x.item;x.item = element;return oldVal;}
指定位置后面添加元素(原索引位置元素以及之后的元素右移,索引位置放置新元素)
/*** 校验index索引是否有效* 判断如果index等于list数组元素数量,就调用linkLast(element) 尾部添加元素* 不等于就调用linkBefore(elemetn,node(index))在元素之前插入*/public void add(int index, E element) {checkPositionIndex(index);if (index == size)linkLast(element);elselinkBefore(element, node(index));}
移除元素
/*** 校验index索引是否有效* 调用unlink(node)方法取消链接*/public E remove(int index) {checkElementIndex(index);return unlink(node(index);}
好了,LinkedList源码按摩就到此结束了,如有错误欢迎指出,共同进步,以便下次提供更好的按摩服务
边栏推荐
- Time series analysis 41 - time series prediction tbats model
- TimeBasedRollingPolicy简介说明
- New features of ES6
- 数据不会说谎,Plato Farm就是元宇宙龙头
- In hot weather, the line of defense for safe production was strengthened, and Guangzhou Haizhu District carried out emergency drills for gas stations
- OSPF的不规则区域,LSA和序列号
- 极致通缩和永动机模型,将推动 PlatoFarm 爆发
- Basic knowledge of redis
- PHP7 中 ?? 与? :的区别
- Sizebasedtriggingpolicy introduction
猜你喜欢

JS promotion: the underlying principle of flat tiling

【学习笔记】border与period

OSS direct upload rails service practice

居家健康诊断时代下,Senzo打造增强侧向流测试产品

Plato Farm-以柏拉图为目标的农场元宇宙游戏

路由器固件解密思路

Software testing and quality learning notes 2 - black box testing

Plato farm - a farm meta universe game with Plato as the goal

并查集

高温持续,公交企业开展安全专项培训
随机推荐
CTF中常见的RSA相关问题总结:基础RSA加密与解密
二分、三分、01分数规划【第III弹】
【JZOF】15二进制中1的位数
超级原始人系列盲盒即将上线,PlatoFarm赋能超多权益
Introduction to evaluatorfilter
Time series analysis 41 - time series prediction tbats model
设计一个支持百万用户的系统
在Plato Farm新经济模型下,如何在游戏中获取更多MARK
2021.07.13 我们是这样崩的
Introduction to consoleappender
【FPGA教程案例41】图像案例1——通过verilog读取图片
Platofarm has made continuous progress, and has launched the official version and super primitive NFT successively
Extreme deflation and perpetual motion machine model will promote the outbreak of platofarm
Openatom openharmony sub forum, see you today at 14:00! Wonderful release of memorabilia attached
How PHP gets the interface
SQL Server、MySQL主从搭建,EF Core读写分离代码实现
OSS direct upload rails service practice
ThresholdFilter简介说明
2022-uni-app解析token标准的方式-使用jsrsasign-爬坑过了
居家健康诊断时代下,Senzo打造增强侧向流测试产品