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底层是通过双向循环链表来实现的,其结构如下图所示: 链表的组成元素我们称之为节点,节点由三部分组成:前一个节点的引用地 ...
随机推荐
- JavaScript原型链:prototype与__proto__
title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...
- .NET框架详解
.NET框架的战略目标 .NET框架的战略目标是在任何时候(When),任何地方(Where),使用任何工具(What)都能通过.NET的服务获得网络上的任何信息,享受网络带给人们的便捷和快乐! .N ...
- WinForm关于listview的用法介绍
public Form1() { InitializeComponent(); //控件的行为 listView1.Bounds = , ), , ));//相对位置 listView1.View = ...
- Sed Awk 日常使用总结
Sed命令语法sed [option] {sed-commands}{input-file}sed首先从input-file中读取第一行,然后执行所有的sed-commands:再读取第二行,执行所有 ...
- VB学习生成JavaBean
Application.ActiveWorkbook.Path 获取当前excel文件所在的文件地址 Excel VBA中表示当前工作簿,有Activeworkbook和Thisworkbook 两种 ...
- [USACO17DEC]Milk Measurement(平衡树)
题意 最初,农夫约翰的每头奶牛每天生产G加仑的牛奶 (1≤G≤109)(1≤G≤10^9)(1≤G≤109) .由于随着时间的推移,奶牛的产奶量可能会发生变化,农夫约翰决定定期对奶牛的产奶量进行测量, ...
- C++ STL rope介绍----可持久化平衡树
大致介绍: rope这个东西,我刚刚知道这玩意,用的不是很多,做个简单的介绍. 官方说明:我是刘邦(我估计你是看不懂的). rope就是一个用可持久化平衡树实现的“重型”string(然而它也可以保存 ...
- 【mysql】新增、修改、删除、查询 语法讲义
一.DML - 数据操作语言 INSERT - 实现数据表数据的新增 UPDATE - 实现数据表数据的修改 DELETE - 实现数据表数据的删除 二.INSERT 语法: insert into ...
- 【Paper Reading】Object Recognition from Scale-Invariant Features
Paper: Object Recognition from Scale-Invariant Features Sorce: http://www.cs.ubc.ca/~lowe/papers/icc ...
- 如何绑定host
绑定host一般分为windows和linux下两种情况. windows下,首先打开host文件,其操作步骤 ,打开 C:\Windows\System32\Drivers\etc\hosts的文件 ...