链表数据结构

  当前节点会保存上一个、下一个节点。 参见 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源码学习的更多相关文章

  1. 基于JDK1.8的LinkedList源码学习笔记

    LinkedList作为一种常用的List,是除了ArrayList之外最有用的List.其同样实现了List接口,但是除此之外它同样实现了Deque接口,而Deque是一个双端队列接口,其继承自Qu ...

  2. 集合框架源码学习之LinkedList

    0-1. 简介 0-2. 内部结构分析 0-3. LinkedList源码分析 0-3-1. 构造方法 0-3-2. 添加add方法 0-3-3. 根据位置取数据的方法 0-3-4. 根据对象得到索引 ...

  3. JDK1.8源码学习-LinkedList

    JDK1.8源码学习-LinkedList 目录 一.LinkedList简介 LinkedList是一个继承于AbstractSequentialList的双向链表,是可以在任意位置进行插入和移除操 ...

  4. [数据结构-线性表1.2] 链表与 LinkedList<T>(.NET 源码学习)

    [数据结构-线性表1.2] 链表与 LinkedList<T> [注:本篇文章源码内容较少,分析度较浅,请酌情选择阅读] 关键词:链表(数据结构)    C#中的链表(源码)    可空类 ...

  5. JDK源码学习笔记——LinkedList

    一.类定义 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E& ...

  6. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  7. JDK源码学习系列05----LinkedList

                                             JDK源码学习系列05----LinkedList 1.LinkedList简介 LinkedList是基于双向链表实 ...

  8. LinkedList源码解读

    一.内部类Node数据结构 在讲解LinkedList源码之前,首先我们需要了解一个内部类.内部类Node来表示集合中的节点,元素的值赋值给item属性,节点的next属性指向下一个节点,节点的pre ...

  9. Java集合框架之二:LinkedList源码解析

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! LinkedList底层是通过双向循环链表来实现的,其结构如下图所示: 链表的组成元素我们称之为节点,节点由三部分组成:前一个节点的引用地 ...

随机推荐

  1. Javascript平稳退化、渐进增强

    平稳退化 : javascript平稳退化就是如果一个浏览器完全不支持js或者禁用js的时候,它的基本功能不会受到任何影响.比方说一个网站使用了大量javascript来优化页面,我们现在把浏览器的j ...

  2. SpringCloud学习笔记(17)----Spring Cloud Netflix之服务网关Zuul的使用

    1. 什么时候Zuul? Zuul是一个基于jvm路由和服务端的负载均衡器,在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架. 路由功能:相当于nginx的反向代理 比如: / 可能需要映射到 ...

  3. AC自动机笔记

    AC自动机 #include<iostream> #include<cstring> #include<cstdio> #include<cmath> ...

  4. 批量删除harbor中的镜像

    一 说明 这个是我第一篇博客,所以我想放上原创的东西,尽管我一直都很担心自己写得太low,但是总要学会尝试,学会改变自己,相信自己.在写这个脚本时,由于我接触LInux不是很多,能力有限,仅仅是为了让 ...

  5. Lorenzini:Laplacian与图上的黎曼-罗赫定理

    前两天去听了一下搞代数几何的Dino Lorenzini在交大的两场讲座(“On Laplacian Of Graphs and Generalization”,“Riemann-Roch Theor ...

  6. 经典C语言编程注意点

    C/C++程序员应聘试题剖析 分中的2分.读者可从本文看到strcpy函数从2分到10分解答的例子,看看自己属于什么样的层次.此外,还有一些面试题考查面试者敏捷的思维能力. 分析这些面试题,本身包含很 ...

  7. Linux初学习

    Linux Linux运行与关闭 Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户.多任务.支持多线程和多 CPU 的操作系统. Linux ...

  8. 【POJ 3714】Raid

    [题目链接]:http://poj.org/problem?id=3714 [题意] 给你两类的点; 各n个; 然后让你求出2*n个点中的最近点对的距离; 这里的距离定义为不同类型的点之间的距离; [ ...

  9. COGS——T 1578. 次小生成树初级练习题

    http://www.cogs.pro/cogs/problem/problem.php?pid=1578 ☆   输入文件:mst2.in   输出文件:mst2.out   简单对比时间限制:1 ...

  10. GNU-libiconv编码转换库的使用举例

    继GDAL库.PROJ库.HDF5库.TINYXML库之后,手上进行的项目又让我碰到了ICONV库.之前花了2天时间没有搞定,在甲方一直催促下,今天又捡起来搞搞,搞了一天最终搞定了.相关心得记录例如以 ...