LinkedList源码学习
链表数据结构
当前节点会保存上一个、下一个节点。 参见 LinkedList的Node类
实现:
1. 内部链表的方式。
1.1 添加元素。追加的方式,创建一个新的节点[Node],用最后一个节点关联新的节点。
1.2 删除元素
1.2.1 通过对象删除。遍历链表,删除第一个匹配的对象
修改链表关联结构
2. 内部是同步[modCount]
2.1 LinkedList数据结构变化的时候,都会将modCount++。
2.2 采用Iterator遍历的元素, next()会去检查集合是否被修改[checkForComodification],如果集合变更会抛出异常
类似于数据库层面的 乐观锁 机制。 可以通过 Iterator的api去删除元素
3. 数组结构,内部存储数据是有序的,并且数据可以为null
源码实现
package xin.rtime.collections.list; import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException; // 链表的源码实现
public class LinkedList<E> { transient int size = ; // 当前链表的size transient Node<E> first; // 首节点 transient Node<E> last; // 尾节点 private int modCount = ; // 结构修改次数 // 添加节点
public boolean add(E e) {
linkLast(e);
return true;
} // 删除节点
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)) { // equals
unlink(x);
return true;
}
}
}
return false;
} // 获取节点
public E get(int index) {
checkElementIndex(index); // 检查元素Index是否存在 , 不存在会抛出数组越界
return node(index).item;
} // 获取链表size
public int size() {
return size;
} public Iterator<E> iterator() {
return listIterator();
} public ListIterator<E> listIterator() {
return listIterator();
} Node<E> node(int index) {
// assert isElementIndex(index); if (index < (size >> )) { // 当前index 小于 当前一半容量的 size
Node<E> x = first; // 当前节点 等于 首节点
for (int i = ; i < index; i++) // 遍历 index -1 次
x = x.next; // x 等于当前节点的下一个节点
return x;
} else { // 大于
Node<E> x = last;
for (int i = size - ; i > index; i--) // 从尾部开始遍历
x = x.prev; // x 等于当前节点的上一个节点
return x;
}
} private void checkElementIndex(int index) {
if (!isElementIndex(index)) // 节点index是否在链表的容量范围内
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
} private boolean isElementIndex(int index) {
return index >= && index < size;
} private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
} // 获得首个节点值
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
} // 获得尾部节点值
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
} // 获得所有节点值
public Object[] toArray() {
Object[] result = new Object[size];
int i = ;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
} public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
} private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
} // 判断当前节点index是否存在
private boolean isPositionIndex(int index) {
return index >= && index <= size;
} private class ListItr implements ListIterator<E> {
private Node<E> lastReturned = null; // 返回的节点
private Node<E> next; // 下个节点
private int nextIndex; // 下个节点 下标
private int expectedModCount = modCount; // 预期的修改次数 = 等于遍历时的修改次数 ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
} public boolean hasNext() {
return nextIndex < size;
} public E next() {
checkForComodification(); // 校验当前链表是否被改动
if (!hasNext())
throw new NoSuchElementException(); lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
} public boolean hasPrevious() {
return nextIndex > ;
} public E previous() {
checkForComodification(); // 校验当前链表是否被改动
if (!hasPrevious())
throw new NoSuchElementException(); lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
} public int nextIndex() {
return nextIndex;
} public int previousIndex() {
return nextIndex - ;
} public void remove() {
checkForComodification(); // 校验当前链表是否被改动
if (lastReturned == null)
throw new IllegalStateException(); Node<E> lastNext = lastReturned.next;
unlink(lastReturned); // 剔除节点
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
} // 当前节点设置值
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
} public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null) // 下一个节点为null
linkLast(e); // 在尾部插入
else
linkBefore(e, next); // 在指定节点之前插入
nextIndex++;
expectedModCount++;
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
} private 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) { // 上一个节点为空
first = next; // 首节点 = 当前节点下一个节点
} else { // 不为空
prev.next = next; // 上一个节点的下一个节点 等于 当前节点的 下一个节点
x.prev = null; // 当前节点的上一个节点置为null gc回收
} if (next == null) { // 下一个节点为空
last = prev; // 最后节点 = 当前节点的上一个节点
} else { // 不为空
next.prev = prev; // 上一个节点的上一个节点 等于 当前节点的上一个节点
x.next = null; // 当前节点的下一个节点置为null gc回收
} x.item = null; // 当前元素置为null gc回收
size--; // 长度 + 1
modCount++; // 修改次数+1
return element;
} // 在链表的尾部插入节点
void linkLast(E e) {
final Node<E> l = last; // 最后一个元素
final Node<E> newNode = new Node<>(l, e, null); // 上一个元素,当前元素,null
last = newNode; // 最后一个节点等新建的节点
if (l == null) // 如果最后一个节点为空
first = newNode; // 出现一个情况: 当链表为空的时候 , first 和 last 都为 newNode
else
l.next = newNode; //最后节点的下一个节点,等于当前节点
size++; // 链表长度+1
modCount++; // 修改次数+1
} // 在指定节点添加上一个节点
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;
else
pred.next = newNode;
size++;
modCount++;
} // 链表节点
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源码学习的更多相关文章
- 基于JDK1.8的LinkedList源码学习笔记
LinkedList作为一种常用的List,是除了ArrayList之外最有用的List.其同样实现了List接口,但是除此之外它同样实现了Deque接口,而Deque是一个双端队列接口,其继承自Qu ...
- 集合框架源码学习之LinkedList
0-1. 简介 0-2. 内部结构分析 0-3. LinkedList源码分析 0-3-1. 构造方法 0-3-2. 添加add方法 0-3-3. 根据位置取数据的方法 0-3-4. 根据对象得到索引 ...
- JDK1.8源码学习-LinkedList
JDK1.8源码学习-LinkedList 目录 一.LinkedList简介 LinkedList是一个继承于AbstractSequentialList的双向链表,是可以在任意位置进行插入和移除操 ...
- [数据结构-线性表1.2] 链表与 LinkedList<T>(.NET 源码学习)
[数据结构-线性表1.2] 链表与 LinkedList<T> [注:本篇文章源码内容较少,分析度较浅,请酌情选择阅读] 关键词:链表(数据结构) C#中的链表(源码) 可空类 ...
- JDK源码学习笔记——LinkedList
一.类定义 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E& ...
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- JDK源码学习系列05----LinkedList
JDK源码学习系列05----LinkedList 1.LinkedList简介 LinkedList是基于双向链表实 ...
- LinkedList源码解读
一.内部类Node数据结构 在讲解LinkedList源码之前,首先我们需要了解一个内部类.内部类Node来表示集合中的节点,元素的值赋值给item属性,节点的next属性指向下一个节点,节点的pre ...
- Java集合框架之二:LinkedList源码解析
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! LinkedList底层是通过双向循环链表来实现的,其结构如下图所示: 链表的组成元素我们称之为节点,节点由三部分组成:前一个节点的引用地 ...
随机推荐
- POJ 1949 DP?
题意: 有n个家务,第i个家务需要一定时间来完成,并且第i个任务必须在它 "前面的" 某些任务完成之后才能开始. 给你任务信息,问你最短需要多少时间来完成任务. 输入: 第一行n个 ...
- Kettle的改名由来
不多说,直接上干货! 当时啊,因为很多开源项目到最后都成了无人管的项目,为了避免这种情况的发生,要尽快为Kettle项目构建一个社区.这就意味着,在随后的几年可能需要回答上千封的电子邮件和论坛帖子.幸 ...
- spring boot integrated mybatis three ways!--转
https://github.com/spring-projects/spring-boot/issues/5400 一.使用mybatis-spring-boot-starter1.添加依赖 org ...
- asp.net mvc5 文件下载上传
下载:是通过点击a标签直接下载的方式,没有其他任何要求,在服务器上存在实体文件,不需要请求后台控制层 前段js: <a id="NF-DownLoad" authorize= ...
- [ Docker ] 映射資料夾
- docker run -v <host path>:<container path> - 例如:docker run -v /home/adrian/data:/data ...
- Linux与Windows信息交互快捷方法
要把windows上的D盘挂载的Linux上,首先要知道windows的用户名和密码 假设用户名是administrator,密码是123456 首先,在linux上创建一个挂载的目标目录 mkdir ...
- HDU 2120 Ice_cream's world I【并查集】
解题思路:给出n对点的关系,求构成多少个环,如果对于点x和点y,它们本身就有一堵墙,即为它们本身就相连,如果find(x)=find(y),说明它们的根节点相同,它们之间肯定有直接或间接的相连,即形成 ...
- eclipse界面更改为黑色
效果如下: 更改很简单,该两个配置就行了,如下图: 1.在window中打开Preferences,然后跟下图一样配置就行了.
- [NOIP2003提高组]侦探推理
题目:洛谷P1039.Vijos P1106.codevs1089. 题目大意:给你一系列证词,要你求出谁是凶手.具体题目见原题. 解题思路:我们枚举犯人和星期,一个一个进行判断.如果成功则记录答案, ...
- Ubuntu 16.04 Chrome浏览器安装flash player插件
1:官网下载插件 flash palyer lash_player_npapi_linux_debug.x86_64.tar.gz 2:解压 提取 libpepflashplayer.so 3:手动 ...