Java集合03

8.LinkedList

1)linkedList底层实现了双向链表双端队列的特点

2)可以添加任意元素(元素可以重复),包括null

3)线程不安全,没有实现同步

  • LinkedList的底层操作机制

    1. LinkedList底层维护了一个双向链表
    2. LinkedList中维护了两个属性first和last,分别指向首节点和尾节点
    3. 每个节点(Node对象)里面又维护了prev、next、item三个属性,其中通过prev指向前一个节点,通过next指向后一个节点,最终实现双向链表。
    4. 所以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); }
}
  1. 在执行LinkedList linkedList = new LinkedList();时,LinkedList底层创建了一个空的列表

  1. 执行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()方法。

  1. 此时last指向的是第一个节点,执行final Node<E> l = last;,则 l 也指向第一个节点。

  2. 再新建一个节点,将 l 设置为新结点的pre,即将新结点的前置节点设置为了第一个节点,将新结点的next设置为空。final Node<E> newNode = new Node<>(l, e, null);

  3. 将last指向新结点

  4. 这里 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指向的双向链表中的第一个节点删除

  1. 首先在removeFirst()方法中将 f 指向第一个节点:final Node<E> f = first;

  2. 然后取出第一个节点的值item:final E element = f.item;

  3. 然后将第一个节点next存储的地址赋给常量next,即将next指向第二个节点:final Node<E> next = f.next;

  4. 然后将第一个节点的值置空,以及将第一个节点指向的地址置空,这样第一节点指向第二节点的next就断开了:f.item = null;

    f.next = null; // help GC

  5. 然后将next的地址赋给first,此时的next已经指向了第二个节点,所以first也指向第二个节点:first = next;

  6. 然后判断next是否为空,即判断删除的节点时候为最后一个节点,如果是,则将last置空;若否则将next指向节点的pre置空,也就是将第二个节点指向第一节点的指针断开。

if (next == null)
last = null;
else
next.prev = null;
  1. 而后链表长度-1,链表操作次数+1

  2. 最后返回删除数据的内容

例子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:

  1. 如果我们改查比较多,选择ArrayList
  2. 如果增删比较多,选择LinkedList
  3. 一般来说,在程序中百分之80到90都是查询,因此大部分情况下会选择ArrayList
  4. 在一个项目中,根据业务灵活查询,也可以两个集合一起用。一个模块使用ArrayList,另一个模块使用LinkedList

day20--Java集合03的更多相关文章

  1. Java集合03——你不得不了解的Map

    Map 在面试中永远是一个绕不开的点,本文将详细讲解Map的相关内容.关注公众号「Java面典」了解更多 Java 知识点. Map Map 是一个键值对(key-value)映射接口: 映射中不能包 ...

  2. Java集合04——fail-fast&fail-safe 详解

    在前几个回合中,我们已经详细了解过了 Java 集合中的List.Set 和 Map,对这部分内容感兴趣的朋友可以关注我的公众号「Java面典」了解.今天我们将为各位介绍集合的失败机制--fail-f ...

  3. Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  4. Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet

    概要 本章是JUC系列中的CopyOnWriteArraySet篇.接下来,会先对CopyOnWriteArraySet进行基本介绍,然后再说明它的原理,接着通过代码去分析,最后通过示例更进一步的了解 ...

  5. Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)

    概要 前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内容包括::1 fail-fast简介2 fail-fast示例 ...

  6. Java 集合系列目录(Category)

    下面是最近总结的Java集合(JDK1.6.0_45)相关文章的目录. 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 03. Java 集合系 ...

  7. Java集合源码分析(三)LinkedList

    LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...

  8. Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例

    概要  前面,我们已经学习了ArrayList,并了解了fail-fast机制.这一章我们接着学习List的实现类——LinkedList.和学习ArrayList一样,接下来呢,我们先对Linked ...

  9. Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

    概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...

随机推荐

  1. webpack.config.js和vue.config.js的区别

    webpack.config.js是webpack的配置文件,所有使用webpack作为打包工具的项目都可以使用,vue的项目可以使用,react的项目也可以使用. vue.config.js是vue ...

  2. Unity实现”对象池管理器“

    前言:警告!这可能是坨屎,空闲时间写成,仅作娱乐 在Unity中生成或销毁一个物体会占用较大的资源,如果是制作FPS射击游戏,子弹生成更是雪上加霜.所以我自己写了一个PoolManager,不能和网上 ...

  3. Linux Cgroup v1(中文翻译)(1):Control Group

    英文原文:https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cgroups.html 1 控制组 1.1 什么是控制组? 控制组 ...

  4. script标签crossorigin属性及同源策略和跨域方法

    首先介绍(同源策略) 同源策略是浏览器最核心且基本的安全约定,要求协议.域名.端口都相同为同源,如果非同源时请求数据浏览器会在控制台抛出跨域异常错误,同源策略是浏览器的行为,即使客户端请求发送了,服务 ...

  5. CentOS8设置国内镜像源(阿里云镜像)

    CentOS8设置国内镜像源(阿里云) 1.备份原有配置 [root@localhost ~]# mkdir /etc/yum.repos.d.bak [root@localhost ~]# mv / ...

  6. Spring基础只是—AOP的概念介绍

    Spring容器包含两个重要的特性:面向切面编程(AOP)和控制反转(IOC).面向切面编程是面向对象(OOP)的一种补充,在面向对象编程的过程中编程针对的目标是一个个对象,而面向切面编程中编程针对的 ...

  7. QQ空间未授权评论_已忽略

    看群友们聊天时发现的, 大概是做了查看了动态访问时间的一个设置, 但是仅自己可见的说说还是被评论了的这么一个问题. 闲的没事就翻了一下找一下问题. 这个方法嘎嘎鸡肋, 可以说完全没用, 交到tsrc, ...

  8. 软件成分分析(SCA)完全指南

    上一篇文章中,我们讨论了 DAST 的概念.重要性及其工作原理.那在开发过程中如何查找开源软件包中的漏洞并学习如何修复?本指南带你一起了解 SCA 工具及其最佳实践. 如今,绝大多数代码驱动的应用程序 ...

  9. p_b_p_b 杂题选讲

    [ARC119F] AtCoder Express 3 [ARC117F] Gateau 考虑二分答案,对前缀和建差分约束 \(\text{check}\) ,但是用 \(\text{spfa}\) ...

  10. appium实现简单的功能测试

    实现思路 思路: 1.获取capabilities信息 2.启动app(包含安装过程) 3.检查是否安装成功 4.卸载app 5.检查是否卸载成功 6.执行×3 from time import sl ...