链表数据结构

  当前节点会保存上一个、下一个节点。 参见 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. 将枚举存入map集合

    遍历枚举存入集合: Map<String,Object> deptLevel = new HashMap<>(); for(OrgBussinessEnum orgBussin ...

  2. .NET框架详解

    .NET框架的战略目标 .NET框架的战略目标是在任何时候(When),任何地方(Where),使用任何工具(What)都能通过.NET的服务获得网络上的任何信息,享受网络带给人们的便捷和快乐! .N ...

  3. Swift学习笔记(8):闭包

    目录: 基本语法 尾随闭包 值捕获 自动闭包 闭包是自包含的函数代码块,闭包采取如下三种形式之一: ・全局函数是一个有名字但不会捕获任何值的闭包 ・嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 ...

  4. C#使用tesseract3.02识别验证码模拟登录

    一.前言 使用tesseract3.02识别有验证码的网站 安装tesseract3.02 在VS nuget 搜索Tesseract即可. 二.项目结构图 三.项目主要代码 using System ...

  5. passwd文件

    1.查看/etc/passwd [admin@localhost /]$ cat -n /etc/passwd 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1: ...

  6. eclipse历史版本下载地址

    http://wiki.eclipse.org/Older_Versions_Of_Eclipse

  7. vue项目测试和打包发布

    在线测试:npm run dev 发布打包:npm run build  打包后,代码文件在dist文件夹下面,可以正式发布了,复制到其它web服务器下面,在浏览器用http访问.

  8. mysql 1067终极解决办法 亲测好使

       进入mysql data 目录 删除 ib_logfile0  ib_logfile1   ibdata1   这三个文件 重启mysql

  9. 浅谈python 中正则的一些函数

         主要的函数有  : match() search() findall() group() groups() split()  match (): 含义  开头匹配,匹配成功返回一个对象失败则 ...

  10. CloudStack云基础架构的一些概念

    1. Zones(区域) 一个区域在CloudStack配置中是最大的组织单元.一个区域通常代表一个单独的数据中心,虽然在一个数据中心也允许有多个区域.将基础架构设施加入到区域中的好处是提供物理隔离和 ...