LinkedList 添加元素源码解析
jdk版本:1.8
LinkedList添加元素有两个方法:add(E e)和add(int index,E e)。
add(E e)
/**
* Appends the specified element to the end of this list.
* 在列表最后添加指定元素
*/
public boolean add(E e) {
linkLast(e);
return true;
}
add(E e)是直接在队尾添加元素。再看一下linkLast(E e)方法,源码如下。
void linkLast(E e) {
//找到链表的最后一个节点,赋值给l,
final Node<E> l = last;
//创建节点,这个节点的上一个节点就是上面last节点
final Node<E> newNode = new Node<>(l, e, null);
//将新的节点赋值给最后节点
last = newNode;
if (l == null)
//如果没有最后节点,表示添加链表为空,赋值给首节点。
first = newNode;
else
//有最后一个节点,将最后节点的next指针指向新建的节点
l.next = newNode;
size++;
modCount++;
}
- LinkedList会记录链表的最后一个节点last,
- 首先创建新的节点,新节点的pre就是队列的最后一个节点last,新节点的next为null,
- 如果last为空表示这个链表为空,新节点就是首节点first。
- 如果last不为空表示链表不为空,将last节点的next指针指向新节点。
add(int index,E e)
add(int index,E e)是根据元素插入到指定位置上,index表示链表的位置
/**
* Inserts the specified element at the specified position in this list.
* 插入指定的元素到列表指定位置上
*/
public void add(int index, E element) {
//检查位置是否越界
checkPositionIndex(index);
//如果插入的下标等于链表的大小,直接就是添加到队尾,
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
- 首先检查index是否超过链表大小,即index 是否会大于链表的size。
- 如果index等于链表的大小,添加元素就是在链表队尾添加元素,和add(E e) 操作一致。
- 如果不等会size大小就调用linkBefore方法,首先在该方法的第二个参数使用了node方法。node方法源码如下:
Node<E> node(int index) {
//size >>1 表示size右移,表示size的一半
//如果index小于size一半,从首节点往后遍历
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
//如果index大于size一半,从最后一个节点往前遍历
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
node方法通过链表的位置找到链表的元素。这里用到了一个size的右移运算,size>>1表示size/2。首先判断index是在链表的前一半还是后一半,因为linkedList是双链表,可以往前和往后进行遍历。如果在前半部分就从首节点往后遍历,如果在后半部分就从最后一个节点往前遍历,这样最多遍历size的一半,避免遍历整个链表。
找到index对应的元素后执行linkedBefore方法
/**
* Inserts element e before non-null Node succ.
* 往succ节点前面插入元素
*/
void linkBefore(E e, Node<E> succ) {
//succ的前一个节点
final Node<E> pred = succ.prev;
//创建新节点,新节点的pre就是succ的pre节点,新节点的next就是succ节点
final Node<E> newNode = new Node<>(pred, e, succ);
//succ.pre指向新节点
succ.prev = newNode;
//如果succ前节点为空,表示succ就是首节点,新节点即为首节点
if (pred == null)
first = newNode;
else
//succ的上一节点的next指向新节点
pred.next = newNode;
size++;
modCount++;
}
- 新建节点,节点pre就是succ的pre,节点的next就是succ。
- 将succ.pre指向新节点。
- succ的pre为null,succ即为首节点,将first赋值给首节点
- succ的pre不为空,则把succ的上一节点的next指向新节点
总结
- LinkedList,只有两种添加方式,一种是在列表最后添加(linkLast),一种是在列表某个元素前面添加 (linkBefore)。
- LinkLast,首先创建一个新节点,节点pre指向最后一个节点,最后一个节点的next指向新节点。
- LinkBefore,首先根据index下标获取到元素的位置,新建新节点,新节点的pre就是元素的pre,新节点的next就是该元素。元素的pre的next指向新元素。
为何Linked要用双链表而不是单链表
LinkedList为何是双链表,链表主要缺点是查询速度很慢,添加或者删除都要找到要添加和删除的节点,而使用双链表,每次遍历循环前,都会判断一下索引是在链表的前半部分还是后半部分。如果是前半部分的话,从首部遍历到中间。如果是后半部分,从尾部遍历到中间。
LinkedList 添加元素源码解析的更多相关文章
- Java集合---LinkedList源码解析
一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clo ...
- 给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析
LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明. 1.链表的概念 链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链 ...
- LinkedList源码解析
LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明.1.链表的概念链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链表又分为单向链表和 ...
- 从源码解析LinkedList集合
上篇文章我们介绍了ArrayList类的基本的使用及其内部的一些方法的实现原理,但是这种集合类型虽然可以随机访问数据,但是如果需要删除中间的元素就需要移动一半的元素的位置,效率低下.并且它内 ...
- ava集合---LinkedList源码解析
一.源码解析 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E ...
- Java集合:LinkedList源码解析
Java集合---LinkedList源码解析 一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据re ...
- Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例
概要 前面,我们已经学习了ArrayList,并了解了fail-fast机制.这一章我们接着学习List的实现类——LinkedList.和学习ArrayList一样,接下来呢,我们先对Linked ...
- Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- 有关LinkedList常用方法的源码解析
上文里解析了有关ArrayList中的几个常用方法的源码——<有关ArrayList常用方法的源码解析>,本文将对LinkedList的常用方法做简要解析. LinkedList是基于链表 ...
随机推荐
- 为ScrollView增加圆角的三种方式,及自定义属性【在Linearlayout中新增ScrollView支持滚动 后续】
获取圆角的几种方案如下:方案一:通过shape来实现,给scrollView增加背景来实现方案二:通过自定义ScrollView,还要自定义属性,在dispatchDraw中不停的裁剪方案三:用And ...
- BUUCTF-[HCTF 2018]admin(Unicode欺骗&伪造session)
目录 方法一:Unicode欺骗 方法二:伪造session 参考文章 记一道flask下session伪造的题. 方法一:Unicode欺骗 拿到题目f12提示you are not admin,显 ...
- 得到、微信、美团、爱奇艺APP组件化架构实践
一.背景 随着项目逐渐扩展,业务功能越来越多,代码量越来越多,开发人员数量也越来越多.此过程中,你是否有过以下烦恼? 项目模块多且复杂,编译一次要5分钟甚至10分钟?太慢不能忍? 改了一行代码 或只调 ...
- 1051 Pop Sequence (25分)栈
刷题 题意:栈的容量是5,从1~7这7个数字,写5个测试数据 做法:模拟栈 #include<bits/stdc++.h> using namespace std; const int m ...
- Maven 下载、安装与配置
一.需要准备的东西 确定电脑上已经成功安装JDK 二.下载与安装 1. 前往https://maven.apache.org/download.cgi下载最新版的Maven程序: 注意:Maven3. ...
- 51单片机—使用PWM对直流电机调速
文章目录 - 什么是PWM - PWM是怎么对直流电机进行调速的 - 通过定时器中断实现PWM调速 - 上代码 - 什么是PWM PWM(脉宽调制),是靠改变脉冲宽度来控制输出电压,通过改变周期来控制 ...
- Longhorn,企业级云原生容器分布式存储 - K8S 资源配置示例
内容来源于官方 Longhorn 1.1.2 英文技术手册. 系列 Longhorn 是什么? Longhorn 企业级云原生容器分布式存储解决方案设计架构和概念 Longhorn 企业级云原生容器分 ...
- Ladp存储规则
Ladp存储规则 区分名(DN,Distinguished Name) 和自然界中的树不同,文件系统/LDAP/电话号码簿目录的每一片枝叶都至少有一个独一无二的属性,这一属性可以帮助我们来区别这些枝叶 ...
- NOIP 模拟 $15\; \text{影子}$
题解 \(by\;zj\varphi\) 一道并查集的题 对于它路径上点权,我们可以转化一下:对于一个点,它在哪些路径上是最小的点权 那么我们排个序,从大到小加入点,每回加入时,将这个点与它所相连的且 ...
- CSS3图片倒影技术
http://bbs.itheima.com/thread-330315-1-1.html?wymlxt