LinkedList的实现源码分析
LinkedList
以双向链表实现。链表无容量限制,但双向链表本身使用了更多空间,也需要额外的链表指针操作。
按下标访问元素--get(i)/set(i,e) 要悲剧的遍历链表将指针移动到位(如果i>数组大小的一半,会从末尾移起)。
插入、删除元素时修改前后节点的指针即可,但还是要遍历部分链表的指针才能移动到下标所指的位置,只有在链表两头的操作--add(), addFirst(),removeLast()或用iterator()上的remove()能省掉指针的移动。
在介绍LinkedList之前我们来回顾下链表的类型,链表主要包含单向链表,单向循环链表,双向链表,双向循环链表。具体的图我就不在这边画出了,不清楚的可以自行百度。LinkedList是属于双向链表,下图是包含头结点和尾节点的双向链表。
![](http://images2015.cnblogs.com/blog/184011/201604/184011-20160412152626332-986071185.jpg)
本篇内容主要讲解下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
下面来看下删除的实现
![](http://images2015.cnblogs.com/blog/184011/201604/184011-20160412152657926-1661468375.jpg)
下面看下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 ...
随机推荐
- IOS开发 图形绘制,绘制线条,矩形,和垂直和居中绘制文字
概述 吐槽下IOS下 的图形绘图,代码冗长,不得不自己重新封装方法.整理形成本文. 绘制线 // 绘制直线 + (void)toDrawLineFromX:(CGFloat)x1 Y:(CGFloat ...
- java-cef系列视频第二集:搭建开发环境
上一集我们介绍了如何从官方代码编译java-cef. 本视频介绍了如何使用eclipse搭建java-cef二次开发环境. 下一集我们将给java-cef添加flash支持. 本作品采用知识共享署名- ...
- 我也要学iOS逆向工程--全局变量
大家好!很久不见了.我之前去音乐学院进修爵士吉他去了.现在回来了.之前我一直在学windows开发和逆向.后来到了音乐学院,老师推荐了1个录音软件叫logic prox.可惜啊!当时我只有个索尼的笔记 ...
- 三种ViewController跳转的异同
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag comple ...
- Cannot open connection 解决办法
试了很多种网上找的办法,都不行,最后才发现是我的beans.xml中完全把下面 这一段代码给遗忘了,忘记写了.添加我就ok了. 我能说花了我近1个小时吗?坑姐哦! <bean class=&qu ...
- CLR via C#深解笔记一 - CLR & C# 基础概念
写在前言 .Net Framework并不是Win 32 API 和COM上的一个抽象层. 某种程度上,它是自己的操作系统,有自己的内存管理器,自己的安全系统,自己的文件加载器,自己的错误处理 ...
- [原]零基础学习视频解码之seek
现在,我们要添加一些功能,当你看不能倒带的电影,是不是很烦? 那么函数av_seek_frame功能看起来是多么赏心悦目. 我们将让左,右箭头来回走在影片中通过一个小的向上和向下箭头很多,其中“三多一 ...
- SQL server 数据库连接方式分析
SQL server 数据库连接方式图示: ODBC和OLEDB连接的区别 ODBC(开放数据库互连):是Microsoft引进的一种早期数据库接口技术.它实际上是ADO的前身.早期的数据库连接是非常 ...
- css3 画圆记录
<style> .radar-wrapper * { -moz-box-sizing: border-box; box-sizing: border-box; margin:; paddi ...
- storm分组模式
Shuffle grouping: Tuples被随机分配到每一个bolt’s task,以便于每一个bolt’s task获得相同数量的tuples. Fields grouping: Stream ...