Debug LinkedList
Debug LinkedList源码
前置知识
- LinkedList基于链表,LinkedList的Node节点定义

成员变量
//链表中元素的数量
transient int size = 0; /**
* 链表的头节点:用于遍历
*/
transient Node<E> first; /**
* 链表的尾节点:用于添加元素
*/
transient Node<E> last;
2.1 Debug 分析第一个元素是如何进入链表的
编写测试代码,打上断点:

进入方法内部:
- add方法默认添加到链表的尾部
- 该方法等同于addLast(区别就是add方法需要返回一个true,而addLast没有任何返回值)


进入linkLast方法内部:
/**
* 当前方法执行完后,若添加的节点为第一个节点,链表的last和first都指向新节点
*/
void linkLast(E e) {
//获取到链表的最后一个元素
final Node<E> l = last;
//创建一个节点,前一个节点为当前链表的last,后一个节点为空
final Node<E> newNode = new Node<>(l, e, null);
//修改last为新添加的节点
last = newNode;
//若链表为空,first节点为新添加的节点,否则添加前最后一个节点的next指向新节点
if (l == null)
first = newNode;
else
l.next = newNode;
//链表长度加一
size++;
//链表修改次数加1
modCount++;
}
//=================================================================
Node带三个参数的构造函数:
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
2.2 Debug 分析如何通过下标插入指定位置add(index,e)
编写测试用例:

进入方法内部:
public void add(int index, E element) {
//检查下标是否合法:大于等于0小于等于size【return index >= 0 && index <= size;】
checkPositionIndex(index);
//若等于size,相当于在链表尾部添加节点
if (index == size)
linkLast(element);
else
//linkBefore中的Before指的是传入索引元素前
linkBefore(element, node(index));
}
进入node(index)方法:返回索引为index的元素
Node<E> node(int index) {
// assert isElementIndex(index);
//查找元素的思路是遍历一半,先折半分区,然后若在小于折半的区域就从first开始往后遍历,反之从last往前遍历
//右移一位相当于除以2
if (index < (size >> 1)) {
//获取到first节点
Node<E> x = first;
//从first遍历到index的位置
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//获取到next的节点
Node<E> x = last;
//从last往前遍历到index的位置
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
回到linkBefore方法:
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
//获取index节点的上一个节点
final Node<E> pred = succ.prev;
//创建新节点,下一个节点指向index节点,上一个节点指向index节点的上一个节点
final Node<E> newNode = new Node<>(pred, e, succ);
//index节点的上一个节点指向变为指向新节点
succ.prev = newNode;
//**若index节点的头节点为空,相当于从头部插入节点,直接将新节点赋给first节点
if (pred == null)
first = newNode;
else
//index的上一个节点的下一个节点指向改为新节点
pred.next = newNode;
//节点长度+1
size++;
//链表修改次数+1
modCount++;
}
2.3 Debug 分析如何通过下标获取指定元素
编写测试代码,打上断点:

进入get方法内部:
public E get(int index) {
//检查下标范围
checkElementIndex(index);
//遍历一半,返回节点的值
return node(index).item;
}
LinkedList支持的查询除了通过下标获取外,还支持getLast和getFirst

get(0)和getFirst时间复杂度有区别吗?
理论上来说,getFirst和getLast都是直接获取到节点,时间复杂度为O(1),而通过get(index)方法查询节点,都会折半后遍历一半的元素,时间复杂度为O(n)。但实际情况下,for循环遍历的第一个元素就100%是头节点或尾节点,不会进入之后的循环,实际运行的也是O(1)。
2.4 Debug 分析如何通过下标删除元素
打上断点:

进入方法内部:
public E remove(int index) {
//检查下标范围
checkElementIndex(index);
//node(index)获取需要删除的节点,折半遍历
return unlink(node(index));
}
进入unlink方法内部:
删除中间元素的过程图:

E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
//若删除的节点为头节点,将当前节点的下一个节点赋值给first节点
first = next;
} else {
//若删除的节点为中间节点,将当前节点的上一个节点的下一个节点指向变为当前节点的下一个节点(step1)
prev.next = next;
//当前节点的上一个节点指向置为null(step2)
x.prev = null;
}
if (next == null) {
//若删除的节点为尾节点,将当前节点的上一个节点赋给last
last = prev;
} else {
//若删除的节点为中间节点,将当前节点的下一个节点的上一个节点指向变为当前节点的上一个节点(step3)
next.prev = prev;
//当前节点的下一个节点指向置为null(step4)
x.next = null;
}
//节点元素内容置为空
x.item = null;
//链表长度-1
size--;
//链表修改次数+1
modCount++;
//返回删除节点内容
return element;
}
2.5 Debug 分析如何通过对象删除节点(内容)

public boolean remove(Object o) {
//若节点为null,从first往下遍历(说明LinkedList是允许为空值的,并且允许多个)
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)) {
unlink(x);
return true;
}
}
}
return false;
}
Debug LinkedList的更多相关文章
- jmeter sampler maven项目排错记
eclipse 创建的maven项目,引入jar包之后出现红色叹号,一直找不到原因,连main方法都无法运行,提示找不到类: 错误: 找不到或无法加载主类 soapsampler.SoapSample ...
- Java集合框架源码分析(2)LinkedList
链表(LinkedList) 数组(array)和数组列表(ArrayList)都有一个重大的缺陷: 从数组的中间位置删除一个元素要付出很大的代价,因为数组中在被删除元素之后的所有元素都要向数组的前端 ...
- java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE 的理解
[2013-12-06 11:06:21,715] [C3P0PooledConnectionPoolManager[identityToken->2tl0n98y1iwg7cbdzzq7a|7 ...
- Java总结 - List实现类ArrayList&LinkedList
本文是根据源码进行学习的,如果我有什么理解不对的地方请多指正,谢谢您 上面基本就是List集合类的类图关系了,图中省略掉了比如Cloneable等标记接口,那么List分别具体的主要实现类有:Arra ...
- 【Java源码】集合类-LinkedList
一.类继承关系 LinkedList和ArrayList都实现了List接口.所以有List的特性,同时LinkedList也实现了Deque,所以它也具有双端队列和栈的特性. public clas ...
- DEBUG ArrayList
1,ArrayList面试必问 说说ArrayList和LinkedList的区别? ArrayList基于数组实现,LinkedList基于链表实现,不同的数据结构决定了ArrayList查询效率比 ...
- Debug HashMap
目录 1,HashMap面试必问 2,Debug源码的心得体会 3,JDK 1.7 3.1 用debug分析一个元素是如何加入到HashMap中的[jdk1.7] 3.2 用debug分析HashMa ...
- Java自学第6期——Collection、Map、迭代器、泛型、可变参数、集合工具类、集合数据结构、Debug
集合:集合是java中提供的一种容器,可以用来存储多个数据. 集合和数组既然都是容器,它们有啥区别呢? 数组的长度是固定的.集合的长度是可变的. 数组中存储的是同一类型的元素,可以存储基本数据类型值. ...
- 记一次debug记录:Uncaught SyntaxError: Unexpected token ILLEGAL
在使用FIS3搭建项目的时候,遇到了一些问题,这里记录下. 这里是发布搭建代码: // 代码发布时 fis.media('qa') .match('*.{js,css,png}', { useHash ...
随机推荐
- webpack4.X + react搭建
环境准备工作:windows7.webStorm 2017.1.4.Nodejs 8.7.0.npm 5.4.2 PS:安装的时我们都带上版本,这样即便webpack版本发生变化,也不会出现版本问题. ...
- 扯淡 Spring BeanDefinition
相关文章 Spring 整体架构 编译Spring5.2.0源码 Spring-资源加载 Spring 容器的初始化 Spring-AliasRegistry Spring 获取单例流程(一) Spr ...
- 简易的java爬虫项目
简易的java爬虫项目 本项目仅供java新手学习交流,由于本人也是一名java初学者,所以项目中也有很多不规范的地方,希望各位高手不吝赐教,在评论区指出我的不足,我会虚心学习: 成果预览: 在开始讲 ...
- 别逃避,是时候来给JVM一记重锤了
今天是猿灯塔“365天原创计划”第2天. 今天讲: 为什么写这个主题呢? 之前看到不少同学在讨论, 今天呢火星哥抽出点时间来帮大家整理一下关于JVM的一些知识点 一.JVM是什 ...
- A*算法求K短路模板 POJ 2449
#include<cstdio> #include<queue> #include<cstring> using namespace std; const int ...
- 前端进阶笔记(一)---JS语言通识
一.语言按照语法分类 1.非形式语言:中文 英文 2.形式语言:乔姆斯基谱系(四种文法 上下文包含文法) 0型 无限制文法 1型 上下文相关文法 2型 上下文无关文法 正则文法 二 产生式(BNF) ...
- Rust String(官方文档翻译)
学习Rust,官方文档全英文,查询不太方便,索性直接翻译完,方便查询使用.有需要自由转载,本人英文水平有限,文档是在谷歌翻译的基础上加个人理解完成,不敢保证正确.文档翻译错误的地方欢迎指出: 原文地址 ...
- 浅析Python垃圾回收机制!
Python垃圾回收机制 目录 Python垃圾回收机制 1. 内存泄露 2. Python什么时候启动垃圾回收机制? 2.1 计数引用 2.2 循环引用 问题:引用计数是0是启动垃圾回收的充要条件吗 ...
- 微服务架构中的BFF到底是啥?
在<技术中台与业务中台都是啥玩意>一文中留下一个问题:BFF是啥?为啥在API网关和业务中台之间加入了一层BFF?考虑到在实际工作中,我的大部分同事都问过这个问题,这里我也总结一下进行答复 ...
- scrapy(三):post请求
-- coding: utf-8 -- ''' QiuBai.py 爬虫文件 ''' -- coding: utf-8 -- import scrapy class PostSpider(scrapy ...