JDK1.7-LinkedList循环链表优化
最近在看jdk1.7的时候,发现LinkedList 和1.6中的变化。
首先,简单介绍一下LinkedList:
LinkedList是List接口的双向链表实现。由于是链表结构,所以长度没有限制;而且添加/删除元素的时候,只需要改变指针的指向(把链表断开,插入/删除元素,再把链表连起来)即可,非常方便,而ArrayList却需要重整数组 (add/remove中间元素)。所以LinkedList适合用于添加/删除操作频繁的情况。
--------------------------------the code --------------------------------
在JDK 1.7之前(此处使用JDK1.6来举例),LinkedList是通过headerEntry实现的一个循环链表的。先初始化一个空的Entry,用来做header,然后首尾相连,形成一个循环链表:
在LinkedList中提供了两个基本属性size、header。
private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
其中size表示的LinkedList的大小,header表示链表的表头,Entry为节点对象。
private static class Entry<E> {
E element; //元素节点
Entry<E> next; //下一个元素
Entry<E> previous; //上一个元素 Entry(E element, Entry<E> next, Entry<E> previous) {
this.element = element;
this.next = next;
this.previous = previous;
}
}
上面为Entry对象的源代码,Entry为LinkedList的内部类,它定义了存储的元素。该元素的前一个元素、后一个元素,这是典型的双向链表定义方式。
每次添加/删除元素都是默认在链尾操作。对应此处,就是在header前面操作,因为遍历是next方向的,所以在header前面操作,就相当于在链表尾操作。
如下面的插入操作addBefore以及图示,如果插入obj_3,只需要修改header.previous和obj_2.next指向obj_3即可。
private Entry<E> addBefore(E e, Entry<E> entry) {
//利用Entry构造函数构建一个新节点 newEntry,
Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
//修改newEntry的前后节点的引用,确保其链表的引用关系是正确的
newEntry.previous.next = newEntry;
newEntry.next.previous = newEntry;
//容量+1
size++;
//修改次数+1
modCount++;
return newEntry;
}
在addBefore方法中无非就是做了这件事:构建一个新节点newEntry,然后修改其前后的引用。
---------------------------------------------
在JDK 1.7,1.6的headerEntry循环链表被替换成了first和last组成的非循环链表。
transient int size = 0; /**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first; /**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
在初始化的时候,不用去new一个Entry。
/**
* Constructs an empty list.
*/
public LinkedList() {
}
在插入/删除的时候,也是默认在链尾操作。把插入的obj当成newLast,挂在oldLast的后面。另外还要先判断first是否为空,如果为空则first = obj。
如下面的插入方法linkLast,在尾部操作,只需要把obj_3.next指向obj_4即可。
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
其中:
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;
}
}
---------------------------------------------
To sum up: 【1.6-header循环链表】 V.S 【1.7-first/last非循环链表】
JDK 1.7中的first/last对比以前的header有下面几个好处:
1、 first / last有更清晰的链头、链尾概念,代码看起来更容易明白。
2、 first / last方式能节省new一个headerEntry。(实例化headerEntry是为了让后面的方法更加统一,否则会多很多header的空校验)
3、 在链头/尾进行插入/删除操作,first /last方式更加快捷。
【插入/删除操作按照位置,分为两种情况:中间 和 两头。
在中间插入/删除,两者都是一样,先遍历找到index,然后修改链表index处两头的指针。
在两头,对于循环链表来说,由于首尾相连,还是需要处理两头的指针。而非循环链表只需要处理一边first.previous/last.next,所以理论上非循环链表更高效。恰恰在两头(链头/链尾) 操作是最普遍的】
(对于遍历来说,两者都是链表指针循环,所以遍历效率是一样的。)
JDK1.7-LinkedList循环链表优化的更多相关文章
- JDK1.8 LinkedList双向链表源码
序言 LinkedList是一个双向链表 也就是说list中的每个元素,在存储自身值之外,还 额外存储了其前一个和后一个元素的地址,所以也就可以很方便地根据当前元素获取到其前后的元素 链表的尾部元素的 ...
- Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- ReentrantLock源码分析--jdk1.8
JDK1.8 ArrayList源码分析--jdk1.8LinkedList源码分析--jdk1.8HashMap源码分析--jdk1.8AQS源码分析--jdk1.8ReentrantLock源码分 ...
- 面试:在面试中关于List(ArrayList、LinkedList)集合会怎么问呢?你该如何回答呢?
前言 在一开始基础面的时候,很多面试官可能会问List集合一些基础知识,比如: ArrayList默认大小是多少,是如何扩容的? ArrayList和LinkedList的底层数据结构是什么? Arr ...
- 去年去阿里面试,被问到ArrayList和LinkedList,我是这样回答的!
前言 在一开始基础面的时候,很多面试官可能会问List集合一些基础知识,比如: ArrayList默认大小是多少,是如何扩容的? ArrayList和LinkedList的底层数据结构是什么? Arr ...
- ArrayList 和 LinkedList的执行效率比较
一.概念: 一般我们都知道ArrayList* 由一个数组后推得到的 List.作为一个常规用途的对象容器使用,用于替换原先的 Vector.允许我们快速访问元素,但在从列表中部插入和删除元素时,速度 ...
- Jdk1.8中的HashMap实现原理
HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变. HashM ...
- JDK1.8 HashMap源码分析
一.HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时 ...
- 【1】JDK8 HashMap扩容优化
JDK1.7 VS JDK1.8 比较 优化概述: resize 扩容优化 引入了红黑树,目的是避免单条链表过长而影响查询效率 解决了resize时多线程死循环问题,但仍是非线程安全的 这里主要讲讲扩 ...
随机推荐
- 超强vim配置
在网上找vim的配置,自己配置的特别丑 安装起来也超级方便. #!/bin/bash echo "安装将花费一定时间,请耐心等待直到安装完成^_^" if which apt-ge ...
- [转]Socket send函数和recv函数详解
1.send 函数 int send( SOCKET s, const char FAR *buf, int len, int flags ); 不论是客户还是服务器应用程序都用send函数来向TCP ...
- ASP.NET四则运算--策略模式
在ASP.NET中实现四则运算,同样使用了类的封装,以及策略模式.只不过是把封装的类.前台代码以及后台的代码分离开来,但同样是要达到功能的实现. Calculator.cs using System; ...
- kaili 2.0 开启ssh远程
第一步:更改sshd_config文件
- Python入门-引号
Python 接收单引号(' ),双引号(" ),三引号(''' """) 来表示字符串,引号的开始与结束必须的相同类型的. 其中三引号可以由多行组成,编写多行 ...
- KaliLinux装好系统后安装常用软件
1.配置软件源 leafpad /etc/apt/source.list or(recommand):#官方源deb kali main non-free contribdeb-src kali ma ...
- 几种HtmlEncode的区别(转)
一.C#中的编码 HttpUtility.HtmlDecode.HttpUtility.HtmlEncode与Server.HtmlDecode.Server.HtmlEncode与HttpServe ...
- Vnc viewer与windows之间的复制粘贴
用VNC连接到Linux之后,最纠结的问题就是无法复制粘贴.其实很简单,在Linux里面,打开一个终端,然后输入命令: vncconfig 之后,会弹出一个窗口 不要关闭那个小窗口 之后,就可以愉快的 ...
- GFS Google File System(中文翻译)
Google文件系统 GFS是一个可扩展的分布式文件系统,用于大型的.分布式的.对大量数据进行访问的应用.它运行于廉价的普通硬件上,但可以提供容错功能.它可以给大量的用户提供总体性能较高的服务. 1. ...
- hdu 1573 X问题
数论题,本想用中国剩余定理,可是取模的数之间不一定互质,用不了,看到网上有篇文章写得很好的:数论——中国剩余定理(互质与非互质),主要是采用合并方程的思想: 大致理解并参考他的代码后便去试试hdu上这 ...