LinkedList的实现源码分析
LinkedList
以双向链表实现。链表无容量限制,但双向链表本身使用了更多空间,也需要额外的链表指针操作。
按下标访问元素--get(i)/set(i,e) 要悲剧的遍历链表将指针移动到位(如果i>数组大小的一半,会从末尾移起)。
插入、删除元素时修改前后节点的指针即可,但还是要遍历部分链表的指针才能移动到下标所指的位置,只有在链表两头的操作--add(), addFirst(),removeLast()或用iterator()上的remove()能省掉指针的移动。
在介绍LinkedList之前我们来回顾下链表的类型,链表主要包含单向链表,单向循环链表,双向链表,双向循环链表。具体的图我就不在这边画出了,不清楚的可以自行百度。LinkedList是属于双向链表,下图是包含头结点和尾节点的双向链表。

本篇内容主要讲解下LinkedList这个双向链表在java的源码的实现,主要包含有add,remove,get,set等方法的介绍。
首先我们来看下add方法的实现,下图演示了下节点插入的过程,包含了4个步骤。
我们来看下java的源码,从代码可知insert节点是查在链表尾部的
```java
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node l = last;
final Node newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
private static class Node {
E item;
Node next;
Node prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
<p>因为add(E e)是插在末尾,所以实际上我们只需要做两部操作,吧NewNode的prew指向最后一个节点,把最后一个几点的next指向newNode
```java
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
上面的insertBefore就是执行4个操作了:
1.把新节点newNode的prev指向succ.prev
2.把succ.prev的next执行newNode
3.newNode的next指向succ
4.succ的prev指向newNode
第3、4步已经在Node的构造函数做了,java是执行顺序是3、4、1、2
下面来看下删除的实现

下面看下java的实现,具体下面代码逻辑很简单,就是获取要删除的节点x的prev节点为prev,x的下节点为next。
然后按如图执行prev.next=next;next.prev=prev;
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
set和get函数
```java
public E set(int index, E element) {
checkElementIndex(index);
Node x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
这个两个函数都用到了node函数,又都要用到查询,所以首先要判断index是否大于index/2,大于的话就从尾节点开始查,反正从前节点查。
```java
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;
}
}
这样的设计可以提高查询效率,时间复杂度为O(n/2)。
参考
数据结构与算法分析_java语言描述(第2版).韦斯
LinkedList的实现源码分析的更多相关文章
- ArrayList、LinkedList和Vector源码分析
ArrayList.LinkedList和Vector源码分析 ArrayList ArrayList是一个底层使用数组来存储对象,但不是线程安全的集合类 ArrayList的类结构关系 public ...
- LinkedList详解-源码分析
LinkedList详解-源码分析 LinkedList是List接口的第二个具体的实现类,第一个是ArrayList,前面一篇文章已经总结过了,下面我们来结合源码,学习LinkedList. 基于双 ...
- ArrayList和LinkedList和Vector源码分析
ArrayList源码: private static final int DEFAULT_CAPACITY = 10;//默认长度 /** * Shared empty array instance ...
- LinkedList 源码分析(JDK 1.8)
1.概述 LinkedList 是 Java 集合框架中一个重要的实现,其底层采用的双向链表结构.和 ArrayList 一样,LinkedList 也支持空值和重复值.由于 LinkedList 基 ...
- java集合源码分析(六):HashMap
概述 HashMap 是 Map 接口下一个线程不安全的,基于哈希表的实现类.由于他解决哈希冲突的方式是分离链表法,也就是拉链法,因此他的数据结构是数组+链表,在 JDK8 以后,当哈希冲突严重时,H ...
- 【集合框架】JDK1.8源码分析之LinkedList(七)
一.前言 在分析了ArrayList了之后,紧接着必须要分析它的同胞兄弟:LinkedList,LinkedList与ArrayList在底层的实现上有所不同,其实,只要我们有数据结构的基础,在分析源 ...
- Java源码分析之LinkedList
LinkedList与ArrayList正好相对,同样是List的实现类,都有增删改查等方法,但是实现方法跟后者有很大的区别. 先归纳一下LinkedList包含的API 1.构造函数: ①Linke ...
- LinkedList其实就那么一回事儿之源码分析
上篇文章<ArrayList其实就那么一回儿事儿之源码分析>,给大家谈了ArrayList, 那么本次,就给大家一起看看同为List 家族的LinkedList. 下面就直接看源码吧: p ...
- Java集合源码分析(二)Linkedlist
前言 前面一篇我们分析了ArrayList的源码,这一篇分享的是LinkedList.我们都知道它的底层是由链表实现的,所以我们要明白什么是链表? 一.LinkedList简介 1.1.LinkedL ...
随机推荐
- jQuery 焦点图 旋转木马
jQuery BxSlider 滑动滚动效果 jQuery Easing 动画效果扩展
- Spark源码系列(八)Spark Streaming实例分析
这一章要讲Spark Streaming,讲之前首先回顾下它的用法,具体用法请参照<Spark Streaming编程指南>. Example代码分析 val ssc = )); // 获 ...
- How to Debug Enterprise Portal Code in Dynamics AX 2009
转载 To set up debugging for pages1. Log into the server that is running the AOS.2. Open the Microsoft ...
- [英] 推荐 15 个 jQuery 选择框插件
jQuery Selectbox Plugins let you create beautiful and eye catching select box for your websites inst ...
- 让我们一起Go(十二)
前言: 上篇中,我们讲到了在Go语言中如何定义方法,今天,我们将进一步深入Go语言的面向对象编程. 一.Go语言中的接口 首先来看一个最基本的接口: 和定义一个结构体类似,只不过将struct换成了i ...
- 装B必备词汇
这个页面用来记录遇到的所有高大上的词汇,本词汇集仅限于装B圈交流和讨论. 一致性 hash 算法(consistent hashing) http://blog.csdn.net/sparkliang ...
- label标签跳出循环
出场: 首先我们来说说为什么需要label标签,虽然我们已经知道有break,continue跳出循环,但如果是多重循环那么它们就显的无能为力了,所以就出现了label这个标签来为我们服务. 我们先来 ...
- 看那记不住命令的猿,如何使用GitHub
什么是GitHub呢? GitHub是什么?好吧, 请看百科:http://baike.baidu.com/view/3366456.htm 准备:msysgit.tortoisegit 首先,我们得 ...
- ReflectionToStringBuilder
1. 使用背景 后台接口需要在接口调用的初期,记录下面查询(修改)对象的参数. 2. 使用方法 通过Apache 工具类 输出entity对象所有属性值 <dependency> < ...
- gulp-imagemin图片压缩----gulp系列(三)
本节实现图片压缩,在实现压缩前,先配置images任务,设置源目录和输出目录. 在系列(二)代码的基础上,再进行扩展. 1.找到gulp->config.js,对images进行源目录(src- ...