Java LinkedList【笔记】
Java LinkedList【笔记】
LinkedList
LinkedList 适用于要求有顺序,并且会按照顺序进行迭代的场景,依赖于底层的链表结构
LinkedList基本结构
LinkedList 底层数据结构是一个双向链表
链表每个节点叫做 Node,Node 有 prev 属性,代表前一个节点的位置,next 属性,代表后一个节点的位置
双向链表的头节点(first)的前一个节点是 null
双向链表的尾节点(last)的后一个节点是 null
当链表中没有数据时,first 和 last 是同一个节点,前后指向都是 null
因为是个双向链表,只要机器内存足够强大,是没有大小限制的
链表中的元素叫做 Node,初始化参数的顺序为前一个节点,本身节点值,后一个节点
LinkedList追加节点(新增节点)
在LinkedList追加节点的时候,可以选择追加到链表头部,也可以选择追加到链表尾部,add是默认为尾部追加,addfirst是从头部追加
从头部开始追加(add)
简单来说,尾部追加节点只需要把指向位置修改下就行了
具体操作,我们首先需要将尾节点的数据暂时存储起来,然后建立一个新的节点,初始化,需要注意,新节点的前一个节点的值为尾节点值,新增节点的后一个节点为nul,然后将新建的节点追加到尾部,如果链表为空,头部和尾部都是同一个节点,都是新建的节点,否则把前尾节点的下一个节点指向当前尾节点
源码:
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
从头部追加的方法(addfirst)
将头节点赋值给临时变量,然后新建节点,前一个节点指向null,新建节点的下一个节点的值为头节点的值,然后将新建节点变成头节点,如果头节点为空,那么就是链表为空,头尾节点就是一个节点,此时上一个头节点的前一个节点就指向当前节点
源码:
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
通过这两个方法的对比,可以发现头部追加节点和尾部追加节点是非常相像的,前者是移动头节点的 prev 指向,后者是移动尾节点的next指向
LinkedList节点删除
和追加有一些类似,也是可以选择从头部删除或者是从尾部删除,删除的时候会把节点的值以及前后指向节点都变为null,这样有利于垃圾回收(GC)
从头部删除的话,首先我们先拿出头节点的值来作为方法的返回值,拿出头节点的下一个节点来,将前后设为null帮助垃圾回收,然后头节点的下一个节点成为头节点,如果next为空,则说明链表为空,如果链表不为空,则将头节点的下一个节点指向null,然后修改一下链表大小
源码:
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null;
first = next;
if (next == null)
last = null;
null
else
next.prev = null;
size--;
modCount++;
return element;
}
可以发现,链表结构的节点新增和删除都只需要将前后节点的指向修改下就可以,这说明LinkedList的新增和删除速度很快
LinkedList节点查询
链表的查询是比较慢的,而在LinkedList中进行节点查询不是按照从头循环到尾的方法,而是用的简单二分法,先看index是在链表的前半部分还是后半部分,如果是前半边,就从头找,如果是后半边,就从尾找,这样可以提高一些性能,而且因为链表的性质,即只能从第一个或者最后一个去访问其他的元素,所以简单二分法已经是最优解了
源码:
Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
LinkedList中的接口的新增方法

LinkedList迭代器
LinkedList使用ListIterator迭代接口来实现双向的迭代访问,这个接口提供了向前以及向后的迭代方法

从头到尾的方向的迭代
首先判断一下有没有下一个元素,如果下一个节点的索引小于链表的大小,那么就说明有下一个元素,然后我们取一个元素,看一下版本号有无变化,然后再检查一遍,next是当前的节点,在上一次执行next()方法的时候被赋值的,如果是第一次执行,那么就是在初始化迭代器的时候被赋值的,然后next是下一个节点,为下一次的迭代做准备
源码:
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
从尾到头的迭代
首先我们要确定上次节点的索引位置,如果上次节点索引位置大于0,那么就代表有节点可以迭代,然后我们取前一个节点,同样检查版本号,在next为空的时候,有两个可能,第一个,说明这是第一次迭代,取尾节点,第二个,上次操作的时候把尾节点删掉了,而在next不为空的时候,这就说明已经发生过迭代,直接去前一个节点就可以了,然后改变索引位置
源码:
public boolean hasPrevious() {
return nextIndex > 0;
}
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
(next.prev)
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
一些问题:
ArrayList 和 LinkedList 有何异同?
不同:
底层数据结构方面
ArrayList 底层是数组
LinkedList 底层是双向链表
应用场景方面
ArrayList 更适合于快速的查找匹配,不适合频繁新增删除
LinkedList 更适合于经常新增和删除,对查询反而很少的场景
相同:
最大容量
ArrayList 有最大容量的,为 Integer 的最大值,大于这个值 JVM 是不会为数组分配内存空间的
LinkedList 底层是双向链表,理论上可以无限大,但是实际上,LinkedList 实际大小用的是 int 类型,这也说明了 LinkedList 不能超过 Integer 的最大值,不然会溢出
** null 值**
ArrayList 允许 null 值新增,也允许 null 值删除
LinkedList 新增删除时对 null 值没有特殊校验,是允许新增和删除的。
线程安全
当两者作为非共享变量时,比如说仅仅是在方法里面的局部变量时,是没有线程安全问题的,只有当两者是共享变量时,才会有线程安全问题

Java LinkedList【笔记】的更多相关文章
- Java开发笔记(六十七)清单:ArrayList和LinkedList
前面介绍了集合与映射两类容器,它们的共同特点是每个元素都是唯一的,并且采用二叉树方式的类型还自带有序性.然而这两个特点也存在弊端:其一,为啥内部元素必须是唯一的呢?像手机店卖出了两部Mate20,虽然 ...
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- 20145330第五周《Java学习笔记》
20145330第五周<Java学习笔记> 这一周又是紧张的一周. 语法与继承架构 Java中所有错误都会打包为对象可以尝试try.catch代表错误的对象后做一些处理. 使用try.ca ...
- Java学习笔记4
Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...
- Java开发笔记(序)章节目录
现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...
- Java开发笔记(七十)Java8新增的几种泛型接口
由于泛型存在某种不确定的类型,因此很少直接运用于拿来即用的泛型类,它更经常以泛型接口的面目出现.例如几种基本的容器类型Set.Map.List都被定义为接口interface,像HashSet.Tre ...
- JAVA自学笔记15
JAVA自学笔记15 @例题1:共有5个学生,请把五个学生的信息存储到数组中,并遍历数组,并获取每个学生的信息 Students[] students=new Student[5]; Student ...
- JAVA自学笔记19
JAVA自学笔记19 1.集合总结 Collection(单列集合) List(有序可重复) ArrayList:底层数据结构是数组 ,查询快,增删慢.线程不安全,效率高 Vector:底层数据结构是 ...
- JAVA自学笔记17
JAVA自学笔记17 1.Map接口 1)概述 将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值.可以存储键值对的元素 2)与Collection接口的不同: ①Map是双列的 ...
随机推荐
- 其他:压力测试Jmeter工具使用
下载路径: http://yd01.siweidaoxiang.com:8070/jmeter_52z.com.zip 配置汉化中文: 找到jmeter的安装目录:打开 \bin\jmeter.pro ...
- {"errcode":40017,"errmsg":"invalid button type hint: [I8nq_a0783sha1]"}
在开发微信公众号 添加菜单时遇到问题 一直提示:{"errcode":40017,"errmsg":"invalid button type hint ...
- 《基于JQuery和CSS的特效整理》系列分享专栏
<基于JQuery和CSS的特效整理>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read/201724.html 文章 一款基于jQue ...
- 远程连接Linux上的MongoDB服务
1.Linux环境上安装好MongoDB,并配置好环境变量 2.启动MongoDB 注:mongod /opt/michael/mongodb/mongodb-linux-x86_64-4.0.5/d ...
- mysql 远程登录 10038提示,无法连接
mysql 默认使用端口3306 MYSQL服务器:WIN7 控制面板,WINDOWS防火墙--高级设置--入站规则--新建规则--端口--TCP-特定本地端口--3306--允许连接--下一步,至完 ...
- Java基础00-方法引用32
1. 方法引用 Java8新特征之方法引用 1.1 体验方法引用 代码示例: 需求: 1:定义一个接口(Printable):里面定义一个抽象方法: void printString(String s ...
- 基于SSM酒店管理系统mysql版本(前后台)
介绍:spring,springmvc,mybatis,mysql,eclipse 截图: 数据库表:CREATE TABLE `account` ( `id` int(11) NOT NULL AU ...
- 常用js代码积累
1,js判断进入可视区,参考(亲测不行):https://www.cnblogs.com/Marydon20170307/p/8830069.html 重点学习的话,可参考: js计算元素距离顶部的高 ...
- 详述 IntelliJ IDEA 远程调试 Tomcat 的方法
首先,配置remote: 如上图所示,点击Edit Configurations,进入如下界面: 如上图所示,我们进入了Run/Debug Configurations界面,然后点击左上角的+,选择R ...
- 一定要收藏的5个优秀的SpringCloud开源项目
上一期为大家推荐了几个前端模板,没看过的点下面 一定要收藏的5个后台管理系统的前端框架 今天再为大家推荐几个优秀的SpringCloud开源脚手架项目,开箱即用,不管是学习还是开发新项目,都非常不错. ...