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 = 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/570117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nagios使用check_mysql监控mysql

如果没有check_mysql插件&#xff0c;需要安装Mysql数据库 1、建立专用数据库&#xff1a; [rootsvr3 ~]#mysql -u root -pEnter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 51910 Server version: 5.5.3-m3-log Sou…

python_文件操作代码实例

"""提示&#xff1a;代码中的内容均被注释&#xff0c;请参考&#xff0c;切勿照搬""" 1 #文件的打开和关闭2 3 文件对象 open(文件名,使用方式)4 rt&#xff1a;读取一个txt文件5 wt: 只写打开一个txt文件&#xff0c;&#xff08;如果没有该…

nagios远程系统监测服务

nagios全部的服务大致可以分为3大种&#xff1a;第一种是“本地系统监测服务”&#xff0c;就是监测主机Nagios所在主机对自己本地的一些情况的监测&#xff0c;比如本地磁盘占用情况&#xff0c;本地CPU使用情况等等。第二种是“远程系统监测服务”&#xff0c;就是远程主机系…

Spring中@Async

在Java应用中&#xff0c;绝大多数情况下都是通过同步的方式来实现交互处理的&#xff1b;但是在处理与第三方系统交互的时候&#xff0c;容易造成响应迟缓的情况&#xff0c;之前大部分都是使用多线程来完成此类任务&#xff0c;其实&#xff0c;在spring 3.x之后&#xff0c;…

Mysql不能停用

Timeout error occurred trying to start MySQL Daemon.Starting MySQL: [FAILED]

CentOs如何挂载硬盘

远程SSH登录上Centos服务器后&#xff0c;进行如下操作提醒&#xff1a;挂载操作会清空数据&#xff0c;请确认挂载盘无数据或者未使用第一步&#xff1a;列出所有磁盘 命令&#xff1a; ll /dev/disk/by-path 提示&#xff1a;如果无法确认数据盘设备名称&#xff0c;请使…

挂载

df -Th 查看磁盘挂载情况 ls /dev/sdx* fdisk -l 查看分区情况 fdisk /dev/sdb 分区mnpw uuid:设备的唯一号 blkidUUID"0a59654a-6f2c-4bc1-bbaf-df844e60e2e3" UUID"fe8c9dd4-571c-40a4-837a-a4ab6e4ae7e转载于:https://www.cnblogs.com/finddata/p/10041496.h…

一周冲刺计划2//第一天

第二次一周冲刺计划 2018.12.1 今天开展了小组间的站立会议&#xff0c;四个人仔细分析了第一次冲刺计划中软件的不足&#xff0c;对其的不足之处进行了深刻的反省和分析&#xff0c;并做出相应的修改。首先做出UI界面&#xff0c;对界面进行修改。明天对代码进行修改。转载于:…

linux版的navicat提示丢失scilexer.dll

这是由于SELinux阻止了scilexer.dll加载 &#xff0c;只要解除阻止就可以了。命令解除&#xff1a;如果SELinux是处于强制安全模式时需要做getenforce令SELinux处于容许模式setenforce 0chcon -t textrel_shlib_t scilexer.dll的路径

AWS EC2实例Ubuntu系统设置root用户密码并使用root/ubuntu用户登录

参考链接&#xff1a;http://www.wangchao.info/1137.html 注意&#xff1a;链接中写的简化了&#xff0c;其中重启服务的命令似乎不太适用&#xff0c;可能是不通用&#xff0c;我下面描述的方式亲测可行&#xff0c;如有其他疑问请留言&#xff1b; https://blog.csdn.net/p…

最全的纯净系统下载地址

http://msdn.itellyou.cn/?langzh-cn

坑题

题目描述 小姐姐想要配 n 把钥匙&#xff0c;她走过开锁铺问老板价钱&#xff0c;老板是这么说的&#xff1a; 小姐姐想知道完成配n把钥匙的任务最少需要花费多少钱 输入描述: 题目有多组测试数据。第一行输入一个整数T&#xff08;组数少于100组&#xff09;&#xff0c;表示测…

windows 下架设svn服务器

一、准备工作1、获取 Subversion 服务器程序 到官方网站&#xff08;http://www.collab.net/downloads/subversion &#xff09;下载最新的服务器安装程序。目前最新的是1.7.7版本. 2、获取 TortoiseSVN 客户端程序从官方网站 http://tortoisesvn.net/downloads 获取最新的 To…

最简单的nginx教程 - 如何把一个web应用部署到nginx上

Nginx (engine x) 是一个高性能的HTTP和反向代理服务&#xff0c;也是一个IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点&#xff08;俄文&#xff1a;Рамблер&#xff09;开发的&#xff0c;第一个公开版本0.1.0发布于2004年10月4日…

Linux下tomcat的配置

1、安装JDK文件双击jdk-6u33-linux-x64.bin&#xff0c;以以终端方式运行&#xff0c;安装在opt文件夹下在root用户 下&#xff0c;首先添加执行权限代码 chmod x jdk-6u29-linux-i586-rpm.bin 然后执行 ./jdk-6u29-linux-i586-rpm.bin 2.将tomcat解压出来&#xff0c;放在…

修理牧场(哈夫曼树 )

农夫要修理牧场的一段栅栏&#xff0c;他测量了栅栏&#xff0c;发现需要N块木头&#xff0c;每块木头长度为整数L​i​​个长度单位&#xff0c;于是他购买了一条很长的、能锯成N块的木头&#xff0c;即该木头的长度是L​i​​的总和。 但是农夫自己没有锯子&#xff0c;请人锯…

修改FTP服务器端口后无法访问

如果将FTP服务器原先的端口21修改成其他的端口号&#xff0c;那么访问FTP服务器的方式只能是主动访问如果是用浏览器&#xff0c;那么设置如下&#xff1a;打开浏览器&#xff0c;找到“菜单栏”——“工具”——“Internet 选项” ——“高级”&#xff0c;会看到“使用被动FT…

Median(二分+二分)

Median http://poj.org/problem?id3579 Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 11225 Accepted: 4016Description Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of numbers: ∣Xi - Xj∣ (1 ≤ i &#xff1c; j …

VNCServer在Linux下设置

1.检查vnc客户端和服务器是否已经安装&#xff1a; [rootcentos ~]$ rpm -q vnc-server package vnc-server is not installed 说明没有安装 运行yum install vnc-server进行安装 vnc-server-4.0-8.1 说明安装已经安装了 只是没开启服务而已 2. 将用户名称加入到配置…

Judy alpha 第七天

SCRUM 今天 debugger 部分由 Yu Xing 继续完成断点功能&#xff0c;由 Zhiqi Lin 开始实现查看变量功能。项目整体打包测试仍有困难&#xff0c;VS Code extension 的文档质量不佳&#xff0c;大家感到难以调试。成员昨日进展今日任务Zibo Wang协助打包、追踪开发进度协助打包、…