day20--Java集合03
Java集合03
8.LinkedList
1)linkedList底层实现了双向链表和双端队列的特点
2)可以添加任意元素(元素可以重复),包括null
3)线程不安全,没有实现同步
- LinkedList的底层操作机制
- LinkedList底层维护了一个双向链表
- LinkedList中维护了两个属性first和last,分别指向首节点和尾节点
- 每个节点(Node对象)里面又维护了prev、next、item三个属性,其中通过prev指向前一个节点,通过next指向后一个节点,最终实现双向链表。
- 所以LinkedList的元素的添加和删除不是通过数组完成的,相对来说效率较高
8.1双向链表
例子:实现简单的双向链表
package li.collections.list.linkedlist;
public class LinkedListTest {
public static void main(String[] args) {
Node jack = new Node("jack");
Node tom = new Node("tom");
Node marry = new Node("marry");
//连接节点,形成双向链表
//jack-->tom-->marry
jack.next = tom;
tom.pre = jack;
tom.next = marry;
marry.pre = tom;
Node first = jack;//让头节点指向Jack
Node last = marry;//尾节点指向marry
//从头到尾遍历
while (true) {
if (first == null) {
break;
}
System.out.println(first);
first = first.next;
}
System.out.println("==========");
//从尾到头遍历
while (true) {
if (last == null) {
break;
}
System.out.println(last);
last = last.pre;
}
}
}
//定义一个Node对象,表示节点
class Node {
public Object item;//存放数据
public Node next;//指针指向下一个节点
public Node pre;//指针指向上一个节点
public Node(Object name) {
this.item = name;
}
@Override
public String toString() {
return "Node item=" + item;
}
}
例子2:双向链表节点的增加和删除
package li.collections.list.linkedlist;
public class LinkedListTest {
public static void main(String[] args) {
Node jack = new Node("jack");
Node tom = new Node("tom");
Node marry = new Node("marry");
//连接节点,形成双向链表
//jack-->tom-->marry
jack.next = tom;
tom.pre = jack;
tom.next = marry;
marry.pre = tom;
Node last = marry;//尾节点指向marry
//链表添加数据
//要求在tom和marry之间插入一个对象json
Node json = new Node("json");
//指针先连后删
json.pre = tom;
json.next = marry;
marry.pre = json;
tom.next = json;
Node first = jack;//让头节点再次指向Jack
//从头到尾遍历
while (true) {
if (first == null) {
break;
}
System.out.println(first);
first = first.next;
}
}
}
//定义一个Node对象,表示节点
class Node {
public Object item;//存放数据
public Node next;//指针指向下一个节点
public Node pre;//指针指向上一个节点
public Node(Object name) {
this.item = name;
}
@Override
public String toString() {
return "Node item=" + item;
}
}
8.2LinkedList底层结构
常用方法:
例子1:LinkedList双向链表增加数据
package li.collections.list.linkedlist;
import java.util.LinkedList;
public class LinkedListCRUD {
@SuppressWarnings("all")
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
System.out.println("linkedList="+linkedList);
}
}
- 在执行
LinkedList linkedList = new LinkedList();
时,LinkedList底层创建了一个空的列表
- 执行
linkedList.add(1);
时,首先进行自动装箱(略),然后调用底层的add()方法,add()又调用linkLast()方法。
linkLst()方法将新的节点加到双向链表的最后:
首先创建一个node类型的常量 l ,首先将last的地址赋给l,因为刚开始没有数据,last指向null,因此l同样也指向null。
再创建一个新的节点newNode,将add(1)传入的参数赋给newNode,newNode的pre指向l,即指向null,newNode的next也指向null。
然后将last指向newNode
第一次的l指向了null,因此执行first也指向新结点newNode语句
最后是链表长度加1,修改次数modCount加1
所以,第一个节点的时候情况如图:
linkedList.add(2);执行第二次添加操作时,重复上述操作,最后来到linkLast()方法。
此时last指向的是第一个节点,执行
final Node<E> l = last;
,则 l 也指向第一个节点。再新建一个节点,将 l 设置为新结点的pre,即将新结点的前置节点设置为了第一个节点,将新结点的next设置为空。
final Node<E> newNode = new Node<>(l, e, null);
将last指向新结点
这里 l不再指向null,因此执行
l.next=newNode;
语句,因为l这时指向第一个节点,所以执行语句之后第一个节点的next将会指向newNode
例子2:双向链表删除数据
package li.collections.list.linkedlist;
import java.util.LinkedList;
public class LinkedListCRUD {
@SuppressWarnings("all")
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.remove();//这里默认删除第一个节点
System.out.println("linkedList="+linkedList);//linkedList=[2, 3]
}
}
分析unlinkFirst()方法:将f指向的双向链表中的第一个节点删除
首先在removeFirst()方法中将 f 指向第一个节点:
final Node<E> f = first;
然后取出第一个节点的值item:
final E element = f.item;
然后将第一个节点next存储的地址赋给常量next,即将next指向第二个节点:
final Node<E> next = f.next;
然后将第一个节点的值置空,以及将第一个节点指向的地址置空,这样第一节点指向第二节点的next就断开了:
f.item = null;
f.next = null; // help GC
然后将next的地址赋给first,此时的next已经指向了第二个节点,所以first也指向第二个节点:
first = next;
然后判断next是否为空,即判断删除的节点时候为最后一个节点,如果是,则将last置空;若否则将next指向节点的pre置空,也就是将第二个节点指向第一节点的指针断开。
if (next == null)
last = null;
else
next.prev = null;
而后链表长度-1,链表操作次数+1
最后返回删除数据的内容
例子3:其他常用方法
package li.collections.list.linkedlist;
import java.util.Iterator;
import java.util.LinkedList;
public class LinkedListCRUD {
@SuppressWarnings("all")
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
//修改某个节点对象
linkedList.set(1,999);//public E set(int index, E element)
System.out.println("linkedList="+linkedList);//linkedList=[1, 999, 3]
//得到某个节点对象
System.out.println(linkedList.get(1));//得到第二个节点对象 999
//遍历:因为LinkedList实现了List接口,所以LinkedList也可以使用增强for循环和迭代器
// 1.增强for循环
for (Object o:linkedList) {
System.out.println(o);
}
//2.迭代器
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
//3.普通for循环
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
}
}
8.3ArrayList和LinkedList的比较
底层结构 | 增删的效率 | 改查的效率 | |
---|---|---|---|
ArrayList | 可变数组 | 较低:数组扩容 | 较高 |
LinkedList | 双向链表 | 较高:通过链表追加 | 较低 |
如任选择ArrayList和LinkedList:
- 如果我们改查比较多,选择ArrayList
- 如果增删比较多,选择LinkedList
- 一般来说,在程序中百分之80到90都是查询,因此大部分情况下会选择ArrayList
- 在一个项目中,根据业务灵活查询,也可以两个集合一起用。一个模块使用ArrayList,另一个模块使用LinkedList
day20--Java集合03的更多相关文章
- Java集合03——你不得不了解的Map
Map 在面试中永远是一个绕不开的点,本文将详细讲解Map的相关内容.关注公众号「Java面典」了解更多 Java 知识点. Map Map 是一个键值对(key-value)映射接口: 映射中不能包 ...
- Java集合04——fail-fast&fail-safe 详解
在前几个回合中,我们已经详细了解过了 Java 集合中的List.Set 和 Map,对这部分内容感兴趣的朋友可以关注我的公众号「Java面典」了解.今天我们将为各位介绍集合的失败机制--fail-f ...
- Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
概要 本章是JUC系列中的CopyOnWriteArraySet篇.接下来,会先对CopyOnWriteArraySet进行基本介绍,然后再说明它的原理,接着通过代码去分析,最后通过示例更进一步的了解 ...
- Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)
概要 前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内容包括::1 fail-fast简介2 fail-fast示例 ...
- Java 集合系列目录(Category)
下面是最近总结的Java集合(JDK1.6.0_45)相关文章的目录. 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 03. Java 集合系 ...
- Java集合源码分析(三)LinkedList
LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...
- Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例
概要 前面,我们已经学习了ArrayList,并了解了fail-fast机制.这一章我们接着学习List的实现类——LinkedList.和学习ArrayList一样,接下来呢,我们先对Linked ...
- Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例
概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...
随机推荐
- 07makefile文件
makefile 规则: 目标: 依赖 (tab)命令 第一个版本: main: main.c fun1.c fun2.c sum.c gcc -o main main.c fun1.c fun2.c ...
- (十二).NET6 + React :升级!升级!还是***升级!!!+ IdentityServer4实战
一.前言 此篇内容较多,我是一步一个脚印(坑),以至于写了好久,主要是这几部分:后台升级 .NET6 VS2022.前台升级Ant Design Pro V5 .前后台联调 IdentityServ ...
- Java的标识符与关键字
目录 Java关键字 总表:java关键字共53个(其中包含两个保留字const,goto) Java标识符 定义 组成 命名规则 视频课程 Java关键字 Java关键字是电脑语言里事先定义的,有特 ...
- JAVA - 线程从创建到死亡的几种状态都有哪些?
JAVA - 线程从创建到死亡的几种状态都有哪些? 新建( new ):新创建了一个线程对象. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 sta ...
- 物联网无线数传应用中的Modbus通信网关协议到底是什么?
什么是物联网 通信Modbus网关 Modbus协议无线通信网关就是将一种Modbus协议帧转换为其他物联网无线数传协议帧. 比如将Modbus RTU的数据与Modbus TCP数据进行相互转换:也 ...
- B 树的简单认识
理解 B 树的概念 B 树是一种自平衡的查找树,能够保持数据有序.这种数据结构能够让查找数据.顺序访问.插入数据及删除数据的动作,都能在对数时间内完成. 同一般的二叉查找树不同,B 树是一棵多路平衡查 ...
- VMware虚拟机基于contos 7 搭建lnmp环境全过程
这个环境也整了几次了,由于本人比较懒,没有记住.找资料很麻烦,就自己动手咯 1.下载VMware虚拟机 (有注册码) 地址:http://www.zdfans.com/5928.html ...
- ExtJS 同行表单域对齐有误处理办法
更新记录 2022年5月29日 第一次编辑.使用的ExtJS版本:ExtJS 7.4 问题 原本都是显示正常的表单域,比如这些文本框.选择框都是正常. 在用户进行操作,然后显示验证提示后,明显出现了问 ...
- WindowsServer评估版转为正式版并激活
更新记录 本文迁移自Panda666原博客,原发布时间:2021年5月16日. 一般从官网下载的Windows Server版本都是评估试用版本.这时候想转为正式版本,就需要使用转换激活代码.请参照不 ...
- VisionPro · C# · 界面显示视觉结果图像
程序界面通过 CogRecordDisplay 控件显示视觉运行结果图像. 按指定图像显示,代码如下: using System; using System.Windows.Forms; using ...