链表数据结构

  当前节点会保存上一个、下一个节点。 参见 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 = 0;  // 当前链表的size
    transient Node<E> first;  // 首节点
    transient Node<E> last;   // 尾节点private int modCount = 0;  // 结构修改次数// 添加节点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;}// 获取链表sizepublic int size() {return size;}public Iterator<E> iterator() {return listIterator();}public ListIterator<E> listIterator() {return listIterator(0);}Node<E> node(int index) {// assert isElementIndex(index);if (index < (size >> 1)) {   // 当前index 小于 当前一半容量的 sizeNode<E> x = first;  // 当前节点  等于 首节点for (int i = 0; i < index; i++)   // 遍历  index -1 次x = x.next;   // x 等于当前节点的下一个节点return x;} else { // 大于Node<E> x = last;for (int i = size - 1; 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 >= 0 && 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 = 0;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 >= 0 && 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 > 0;}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 - 1;}public void remove() {checkForComodification();  // 校验当前链表是否被改动if (lastReturned == null)throw new IllegalStateException();Node<E> lastNext = lastReturned.next;unlink(lastReturned);   // 剔除节点if (next == lastReturned)next = lastNext;elsenextIndex--;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)  // 下一个节点为nulllinkLast(e);   // 在尾部插入elselinkBefore(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--;  // 长度 + 1modCount++;  // 修改次数+1return element;}// 在链表的尾部插入节点void linkLast(E e) {final Node<E> l = last;  // 最后一个元素final Node<E> newNode = new Node<>(l, e, null);  // 上一个元素,当前元素,nulllast = newNode;  // 最后一个节点等新建的节点if (l == null)  // 如果最后一个节点为空first = newNode;    // 出现一个情况:  当链表为空的时候 , first 和 last 都为 newNodeelsel.next = newNode;   //最后节点的下一个节点,等于当前节点size++;  // 链表长度+1modCount++;  // 修改次数+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;elsepred.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;}}
}

转载于:https://www.cnblogs.com/LuisYang/p/10034601.html

LinkedList源码学习相关推荐

  1. JDK源码学习之Arraylist与LinkedList

    ArrayList和LinkedList是我们在开发过程中常用的两种集合类,本文将从底层源码实现对其进行简单介绍. 下图是Java集合类所涉及的类图. 一.ArrayList 从上面的集合类图可以看出 ...

  2. 从面试角度分析LinkedList源码

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 注:本系列文章中用到的jdk版本均为java8 Linke ...

  3. 集合框架源码学习之HashMap(JDK1.8)

    目录: 0-1. 简介 0-2. 内部结构分析 0-2-1. JDK18之前 0-2-2. JDK18之后 0-3. LinkedList源码分析 0-3-1. 构造方法 0-3-2. put方法 0 ...

  4. Java 集合系列(4): LinkedList源码深入解析1

    戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 概要 前面,我们已经学习了ArrayList,并了解了fail-fast ...

  5. 【Android 源码学习】SharedPreferences 源码学习

    第一章:SharedPreferences 源码学习 文章目录 第一章:SharedPreferences 源码学习 Android SharedPreferences的缺陷 MMKV.Jetpack ...

  6. 【博学谷学习记录】超强总结,用心分享 | 架构师 Mybatis源码学习总结

    Mybatis源码学习 文章目录 Mybatis源码学习 一.Mybatis架构设计 二.源码剖析 1.如何解析的全局配置文件 解析配置文件源码流程 2.如何解析的映射配置文件 Select inse ...

  7. Hadoop HDFS源码学习之NameNode部分

    NameNode源码学习 文章目录 NameNode源码学习 一.文件系统目录树(第一关系) 2.1 INode相关类 2.2 快照特性的实现 2.3 FSEditLog类 2.4 FSImage类 ...

  8. Shiro源码学习之二

    接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...

  9. Shiro源码学习之一

    一.最基本的使用 1.Maven依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId&g ...

最新文章

  1. Linux: debian/ubuntu下安装和使用Java 8
  2. Linux下查找文件方法
  3. 推荐算法矩阵分解实战——keras算法练习
  4. Android可输入的下拉框,android 可编辑的下拉框 Demo
  5. 2020-2021年度第二届全国大学生算法设计与编程挑战赛(春季赛)【部分题题解】
  6. Android 编译系统分析(一)
  7. video和dvd audio区别:
  8. Codeforces Round #626 (Div. 2) D. Present 按位贡献 + 快排新姿势
  9. 如果__name__ =='__main__':在Python中怎么办?
  10. 一点等于多少厘米_马桶知识介绍,你了解马桶多少
  11. Jackson第一篇【JSON字符串、实体之间的相互转换】
  12. java手机音乐文件夹,从原始文件夹打开音乐文件,使用Android上的意图在设备的默认应用程序上播放...
  13. [材料力学]弯扭组合梁实验报告
  14. [ JAVA编程 ] double类型计算精度丢失问题及解决方法
  15. windows中的凭据管理
  16. 安捷伦34401A六位半万用表
  17. 微积分小糊涂源于微积分大糊涂
  18. 你的Web系统真的安全吗?
  19. 利用一般处理程序处理头像的浏览和更新
  20. 扫描电子显微镜基本构造

热门文章

  1. ajax解析json中的对象数组对象,在JQuery中检索json数组后获取json对象Ajax
  2. 计划任务文件 linux,Linux之任务计划
  3. 背计算机专业英语词汇,计算机专业英语词汇1500词(五)
  4. sgm3157功能_SGM3157_SGM3157供应商_价格_Datasheet_pdf资料-IC资料网
  5. 如何使用explain进行SQL语句调优
  6. android web3j 代币查询_使用Web3.js查询以太币和代币余额以及转账
  7. ❤️六W字《计算机基础知识》(四)(建议收藏)❤️
  8. ORACLE 12C采坑之 ORA-12541:TNS:无监听程序
  9. mysql for update场景_一个mysql死锁场景实例分析
  10. ntext在mysql_varchar和text说不清的那些事