【Java源码】集合类-LinkedList
一、类继承关系
LinkedList和ArrayList都实现了List接口。所以有List的特性,同时LinkedList也实现了Deque,所以它也具有双端队列和栈的特性。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
二、类属性
//实际元素个数
transient int size = 0;
//头结点
transient Node<E> first;
//尾结点
transient Node<E> last;
transient表示该域不能被序列化。first,last初始值都是null.
这里有一个内部类Node:
private static class Node<E> {
//数据
E item;
//后继
Node<E> next;
//前驱
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
三、构造函数
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
LinkedList内部的数据结构是一个双向链表,所以不会有ArrayList那样的指定容量构造器。
四、LinkedList如何扩容
- LinkedList内部的数据结构是一个双向链表,既没有初始化大小,也没有扩容机制一说。其大小是需要时才会分配,不需要分配多余的。
五、主要函数
add(E e) 函数
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
//final类型的l节点保存尾结点last
final Node<E> l = last;
//创建一个新的节点newNode,其前驱为l,后继为null
final Node<E> newNode = new Node<>(l, e, null);
//将尾结点赋值为新创建的节点。
last = newNode;
//尾结点为空,第一次添加
if (l == null)
//新建节点为头结点
first = newNode;
else
//否则以前的尾结点的后继指向新节点
l.next = newNode;
//集合大小加1
size++;
//结构性变化加一,目的和ArrayList一样,检查迭代过程中结构变化。
modCount++;
}
add()方法会将新添加的元素添加到链表的尾端。
- 在linkList中,首先会将原来的尾结点last保存在一个不可变的final节点l中。
- 添加的元素会被新建为一个Node节点,其前驱指向以前的尾结点l,其后继为null。
- 然后将尾结点赋值给last,成为新的尾结点。
- 判断以前的尾结点是否为空(第一次添加),如果为空,新建节点就是头结点first。如果尾结点不是空,l.next = newNode;表示以前的尾结点的后继指向新节点。
- 然后LinkedList集合大小加1。modCount++;表示LinkedList集合结构性变化加一,目的和ArrayList一样,检查迭代过程中结构变化。
让我们通过debug看看LinkedList添加元素过程,其结构的变化。
测试代码:
public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<>();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
}
第一次添加后结构为:

第二次添加后结构为:

第三次添加后结构为:

remove(int index) 函数
public E remove(int index) {
//检查是否越界
checkElementIndex(index);
return unlink(node(index));
}
先通过node方法获取index处的节点:
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(index);
//size >> 1 等于 size/2
if (index < (size >> 1)) {
//index在前半部分,从头开始找
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//index在后半部分,从尾开始找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
然后再通过E unlink(Node x)删除这个节点:
/**
* Unlinks non-null node x.
*/
E unlink(Node<E> x) {
// assert x != null;
//x节点的元素
final E element = x.item;
//后继
final Node<E> next = x.next;
//前驱
final Node<E> prev = x.prev;
//x前驱为空,删除的节点是头节点
if (prev == null) {
first = next;
} else {
//x前驱节点的后继节点变为x的后继节点
prev.next = next;
//切断前驱连接
x.prev = null;
}
//x后继为空,删除的节点为尾结点
if (next == null) {
last = prev;
} else {
//x后继节点的前驱变为x的前驱节点
next.prev = prev;
//切断后继连接
x.next = null;
}
//删除节点元素置空
x.item = null;
size--;
modCount++;
return element;
}
- 首先将要删除节点的数据元素、前驱节点,后继节点保存起来。
- 判断删除节点前驱是否为空,如果x前驱为空,则删除的节点是头节点;如果不为空,将x前驱节点的后继节点变为x的后继节点,再通过x.prev = null;切断x节点前驱连接。
- 判断删除节点后继是否为空,如果x后继为空,则删除的节点为尾结点;如果不为空,将x后继节点的前驱变为x的前驱节点,再切断x的后继连接。
- 最后将删除节点元素置空,size减小,modCount增加。
get(int index)函数
public E get(int index) {
//检查索引
checkElementIndex(index);
return node(index).item;
}
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(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;
}
}
通过node(int index)查找index对应的节点,然后返回对应的数据item。其中size >> 1这个是指size右移一位即size/2 。
- 当index在前半部分,就从头开始查找
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
- 当index在后半部分,就从last开始查找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
六、LinkedList性能相关
LinkedList 是不能随机访问的,按照索引访问效率较低,时间复杂度为复杂度为 O(N/2)
因此,LinkedList 删除一个节点的时间复杂度为 O(N) ,效率很高。
【Java源码】集合类-LinkedList的更多相关文章
- 浅析Java源码之LinkedList
可以骂人吗???辛辛苦苦写了2个多小时搞到凌晨2点,点击保存草稿退回到了登录页面???登录成功草稿没了???喵喵喵???智障!!气! 很厉害,隔了30分钟,我的登录又失效了,草稿再次回滚,不客气了,* ...
- 【数据结构】7.java源码关于LinkedList
关于LinkedList的源码关注点 1.从底层数据结构,扩容策略2.LinkedList的增删改查3.特殊处理重点关注4.遍历的速度,随机访问和iterator访问效率对比 1.从底层数据结构,扩容 ...
- Java源码-集合-LinkedList
基于JDK1.8.0_191 介绍 LinkedList是以节点来保存数据的,不像数组在创建的时候需要申请一段连续的空间,LinkedList里的数据是可以存放在不同的空间当中,然后以内存地址作为 ...
- java源码阅读LinkedList
1类签名与注释 public class LinkedList<E> extends AbstractSequentialList<E> implements List< ...
- 如何阅读Java源码 阅读java的真实体会
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比 ...
- 如何阅读Java源码
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动.源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧, ...
- Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库
http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...
- [收藏] Java源码阅读的真实体会
收藏自http://www.iteye.com/topic/1113732 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我 ...
- 【java集合框架源码剖析系列】java源码剖析之TreeSet
本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...
- 【java集合框架源码剖析系列】java源码剖析之HashSet
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...
随机推荐
- knockout Observable Array(监控数组)
Observable Array(监控数组)的作用 列表操作是经常会遇到的一个场景,使用监控数组,你可以: 保存列表对象,并且使用Ko提供的丰富的API操作列表元素(支持内建js Array的方法,以 ...
- PMP项目管理学习笔记(6)——整合管理之制订项目管理计划
制订项目管理计划 输入:项目章程.组织过程资产.企业环境要素.计划过程的输出(): 工具:专家判断 输出:项目管理计划 项目管理计划使你在问题发生之前做出规划 你要在计划过程组中明确如何完成项目——因 ...
- codevs 2046 孪生素数 3 (水题日常)
时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题目描述 Description 在质数的大家庭中,大小之差不超过2的两个质数称它俩为一对孪生素数,如2和3.3和5 ...
- LC.exe 已退出,代码为-1 问题解决
最近一个c#工程,之前编译正常.后重装系统,安装DevExpress后,编译一直失败,并提示"4>C:\Windows\Microsoft.NET\Framework\v4.0.303 ...
- 十分钟搭建App主流框架
搭建主流框架界面 0.达成效果 Snip20150904_5.png 我们玩iPhone应用的时候,有没发现大部分的应用都是上图差不多的结构,下面的TabBar控制器可以切换子控制器,上面又有Navi ...
- (转)SpringMVC学习(八)——SpringMVC中的异常处理器
http://blog.csdn.net/yerenyuan_pku/article/details/72511891 SpringMVC在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常 ...
- vue 组件名和方法名 重名了,报function错误
vue 组件名和方法名 重名了,报function错误
- L2-2 社交集群 (25 分)(一个写挫的并查集)
题目: 思路: 就是一个并查集的裸题,不过在数据查找方面可能不好处理,暴力完全可以解决这个问题啊!! #include <bits/stdc++.h> #include <cstdi ...
- [HIHO] 1048 铺地板
历经千辛万苦,小Hi和小Ho终于到达了举办美食节的城市!虽然人山人海,但小Hi和小Ho仍然抑制不住兴奋之情,他们放下行李便投入到了美食节的活动当中.美食节的各个摊位上各自有着非常多的有意思的小游戏,其 ...
- Go:json(序列化、反序列化)
一.示例 package main import ( "encoding/json" "fmt" ) type Person struct { Name str ...