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的更多相关文章

  1. jmeter sampler maven项目排错记

    eclipse 创建的maven项目,引入jar包之后出现红色叹号,一直找不到原因,连main方法都无法运行,提示找不到类: 错误: 找不到或无法加载主类 soapsampler.SoapSample ...

  2. Java集合框架源码分析(2)LinkedList

    链表(LinkedList) 数组(array)和数组列表(ArrayList)都有一个重大的缺陷: 从数组的中间位置删除一个元素要付出很大的代价,因为数组中在被删除元素之后的所有元素都要向数组的前端 ...

  3. java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE 的理解

    [2013-12-06 11:06:21,715] [C3P0PooledConnectionPoolManager[identityToken->2tl0n98y1iwg7cbdzzq7a|7 ...

  4. Java总结 - List实现类ArrayList&LinkedList

    本文是根据源码进行学习的,如果我有什么理解不对的地方请多指正,谢谢您 上面基本就是List集合类的类图关系了,图中省略掉了比如Cloneable等标记接口,那么List分别具体的主要实现类有:Arra ...

  5. 【Java源码】集合类-LinkedList

    一.类继承关系 LinkedList和ArrayList都实现了List接口.所以有List的特性,同时LinkedList也实现了Deque,所以它也具有双端队列和栈的特性. public clas ...

  6. DEBUG ArrayList

    1,ArrayList面试必问 说说ArrayList和LinkedList的区别? ArrayList基于数组实现,LinkedList基于链表实现,不同的数据结构决定了ArrayList查询效率比 ...

  7. Debug HashMap

    目录 1,HashMap面试必问 2,Debug源码的心得体会 3,JDK 1.7 3.1 用debug分析一个元素是如何加入到HashMap中的[jdk1.7] 3.2 用debug分析HashMa ...

  8. Java自学第6期——Collection、Map、迭代器、泛型、可变参数、集合工具类、集合数据结构、Debug

    集合:集合是java中提供的一种容器,可以用来存储多个数据. 集合和数组既然都是容器,它们有啥区别呢? 数组的长度是固定的.集合的长度是可变的. 数组中存储的是同一类型的元素,可以存储基本数据类型值. ...

  9. 记一次debug记录:Uncaught SyntaxError: Unexpected token ILLEGAL

    在使用FIS3搭建项目的时候,遇到了一些问题,这里记录下. 这里是发布搭建代码: // 代码发布时 fis.media('qa') .match('*.{js,css,png}', { useHash ...

随机推荐

  1. Json序列化帮助类

    public static class Json { public static object ToJson(this string Json) { return Json == null ? nul ...

  2. SpringBoot--swagger搭建、配置及使用

    一. 作用: 1. 接口的文档在线自动生成. 2. 接口测试. 二.模块介绍 Swagger是一组开源项目,其中主要要项目及功能如下: 1.Swagger Codegen: 通过Codegen 可以将 ...

  3. urllib库使用方法

    这周打算把学过的内容重新总结一下,便于以后翻阅查找资料. urllib库是python的内置库,不需要单独下载.其主要分为四个模块: 1.urllib.request——请求模块 2.urllib.e ...

  4. 初至cnblogs —— 博客搬迁

    感觉写博客是一种总结.分享知识的有效方式,于是打算坚持通过博客这一载体来提升自己. 最初通过 Hexo + GitHub Page 来搭建个人博客,但是通过这种方式搭建的博客基本没有访问量.个人感觉没 ...

  5. 告别传统机房:3D 机房数据可视化实现智能化与VR技术的新碰撞

    前言 随着各行业对计算机依赖性的日益提高,计算机信息系统的发展使得作为其网络设备.主机服务器.数据存储设备.网络安全设备等核心设备存放地的计算机机房日益显现出它的重要地位,而机房的环境和动力设备如供配 ...

  6. C++ 不定参数"..."的使用

    #include <iostream> #include <cstdio> #include <cstdarg> #define LEN_MSG_BUFFER 12 ...

  7. SpringMVC+Spring+Hibernate个人家庭财务管理系统

    项目描述 Hi,大家好,今天分享的项目是<个人家庭财务管理系统>,本系统是针对个人家庭内部的财务管理而开发的,大体功能模块如下: 系统管理模块 验证用户登录功能:该功能主要是验证用户登录时 ...

  8. 「疫期集训day7」周期

    我们成功入侵了圣康坦,屋子里到处都是面包,食物,水...现在我们的目标就在眼前----亚眠------鲁道登夫攻势中损失惨重的德国精英兵 今天考试考出了历史最低,原因在于T1签到题挂了,ull真的毒瘤 ...

  9. Python预测2020高考分数和录取情况可能是这样

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:打磨虾 “迟到”了一个月的高考终于要来了. 正好我得到了一份山东新高 ...

  10. React-redux使用

    为什么要使用react-redux 由于redux的store与组件的耦合度太高所以,我们用react官方提供的react-redux可以使两者耦合度降低,更好的实现模块化开发. react-redu ...