LinkedList剖析

第1部分 LinkedList介绍

LinkedList简介

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。

Doubly-linked list implementation of the List and Deque interfaces. Implements all optional list operations, and permits all elements (including null).All of the operations perform as could be expected for a doubly-linked list. Operations that index into the list will traverse the list from the beginning or the end, whichever is closer to the specified index.Note that this implementation is not synchronized. If multiple threads access a linked list concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list:List list = Collections.synchronizedList(new LinkedList(...));The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the Iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs. 
以双向链表实现。链表无容量限制,但双向链表本身使用了更多空间,每插入一个元素都要构造一个额外的Node对象,也需要额外的链表指针操作。
按下标访问元素-get(i)、set(i,e) 要悲剧的部分遍历链表将指针移动到位 (如果i>数组大小的一半,会从末尾移起)。
插入、删除元素时修改前后节点的指针即可,不再需要复制移动。但还是要部分遍历链表的指针才能移动到下标所指的位置。
只有在链表两头的操作-add()、addFirst()、removeLast()或用iterator()上的remove()倒能省掉指针的移动。
Apache Commons 有个TreeNodeList,里面是棵二叉树,可以快速移动指针到位。

LinkedList构造函数   

/*** Constructs an empty list.*/
public LinkedList() {
}/*** Constructs a list containing the elements of the specified* collection, in the order they are returned by the collection's* iterator.** @param  c the collection whose elements are to be placed into this list* @throws NullPointerException if the specified collection is null*/
public LinkedList(Collection<? extends E> c) {this();addAll(c);
}

看一个例子

public class Test {public static void main(String[] args) {List<String> list = new LinkedList<String>();list.add("语文: 1");list.add("数学: 2");list.add("英语: 3");}
}

结构也相对简单一些,如下图所示:
linkedlist

 

第2部分 LinkedList数据结构

java.lang.Object↳     java.util.AbstractCollection<E>↳     java.util.AbstractList<E>↳     java.util.AbstractSequentialList<E>↳     java.util.LinkedList<E>public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}

成员变量

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;
//每一个元素节点
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;}
}

第3部分 LinkedList源码api解析

LinkedList实际上是通过双向链表去实现的。既然是双向链表,那么它的顺序访问会非常高效,而随机访问效率比较低。
    既然LinkedList是通过双向链表的,但是它也实现了List接口{也就是说,它实现了get(int location)、remove(int location)等“根据索引值来获取、删除节点的函数”}。LinkedList是如何实现List的这些接口的,如何将“双向链表和索引值联系起来的”?
    实际原理非常简单,它就是通过一个计数索引值来实现的。例如,当我们调用get(int location)时,首先会比较“location”和“双向链表长度的1/2”;若前者大,则从链表头开始往后查找,直到location位置;否则,从链表末尾开始先前查找,直到location位置。
   这就是“双线链表和索引值联系起来”的方法。

3.1 add方法

/*** Appends the specified element to the end of this list.** <p>This method is equivalent to {@link #addLast}.** @param e element to be appended to this list* @return {@code true} (as specified by {@link Collection#add})*/
public boolean add(E e) {linkLast(e);return true;
}
/*** Links e as last element.*/
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;elsel.next = newNode;size++;modCount++;
}

3.2. set和get函数

/*** Replaces the element at the specified position in this list with the* specified element.** @param index index of the element to replace* @param element element to be stored at the specified position* @return the element previously at the specified position* @throws IndexOutOfBoundsException {@inheritDoc}*/
public E set(int index, E element) {checkElementIndex(index);Node<E> x = node(index);E oldVal = x.item;x.item = element;return oldVal;
}
/*** Returns the element at the specified position in this list.** @param index index of the element to return* @return the element at the specified position in this list* @throws IndexOutOfBoundsException {@inheritDoc}*/
public E get(int index) {checkElementIndex(index);return node(index).item;
}    
private void checkElementIndex(int index) {if (!isElementIndex(index))throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}/*** Tells if the argument is the index of an existing element.*/
private boolean isElementIndex(int index) {return index >= 0 && index < size;
}

这两个函数都调用了node函数,该函数会以O(n/2)的性能去获取一个节点,具体实现如下所示:

/*** 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;}
}

就是判断index是在前半区间还是后半区间,如果在前半区间就从head搜索,而在后半区间就从tail搜索。而不是一直从头到尾的搜索。如此设计,将节点访问的复杂度由O(n)变为O(n/2)。

总结:
(01) LinkedList 实际上是通过双向链表去实现的。

        它包含一个非常重要的内部类:Node。Node是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值,上一个节点,下一个节点。
(02) 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
(03) LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。
(04) 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。
总结起来如下表格:

        第一个元素(头部)                 最后一个元素(尾部)抛出异常        特殊值            抛出异常        特殊值
插入    addFirst(e)    offerFirst(e)    addLast(e)        offerLast(e)
移除    removeFirst()  pollFirst()      removeLast()    pollLast()
检查    getFirst()     peekFirst()      getLast()        peekLast()

(05) LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下表的方法等价:

队列方法       等效方法
add(e)        addLast(e)
offer(e)      offerLast(e)
remove()      removeFirst()
poll()        pollFirst()
element()     getFirst()
peek()        peekFirst()

(06) LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:

栈方法        等效方法
push(e)      addFirst(e)
pop()        removeFirst()
peek()       peekFirst()

第4部分 LinkedList遍历方式

LinkedList遍历方式

LinkedList支持多种遍历方式。建议不要采用随机访问的方式去遍历LinkedList

//不可取
for (int i = 0; i < linkList.size(); i++) {link = linkList.get(i);
}

一般使用增强的for循环(foreach)

参考:

http://www.cnblogs.com/skywang12345/p/3308807.html

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/261781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

powerdesigner怎么导出pdf_各种科研绘图软件中的矢量图导出技巧

引言科技论文常含有插图&#xff0c;借助插图来形象直观、简明扼要地表达所要表述的内容(梁福军. 科技论文规范写作与编辑[M]. 清华大学出版社, 2014.)。科研绘图软件有很多种&#xff0c;而软件导出的图片可以分为矢量图&#xff08;vector&#xff09;和位图&#xff08;bitm…

Typesafe公司正式更名为Lightbend公司

Scala编程语言的发明者&#xff1a;Typesafe公司&#xff0c;已经完成他们的更名计划&#xff0c;改名后成为Lightbend公司。Typesafe公司在去年五月就宣布了他们的更名计划&#xff0c;从那时起&#xff0c;他们希望可以在两个月内完成改名相关事宜。Typesafe公司邀请了社区的…

理解Javascript_12_执行模型浅析

大家有没有想过&#xff0c;一段javascript脚本从载入浏览器到显示执行都经过了哪些流程&#xff0c;其执行次序又是如何。本篇博文将引出javascript执行模型的概念&#xff0c;并带领大家理解javascript在执行时的处理机制。 简单的开始 简单的代码&#xff1a; <script ty…

怎么制作铁闸门_“短笛”拿铁,最近的心头好!

其实花式咖啡除了市面上一些常见的款式外&#xff0c;还有一些是不常见又好喝的&#xff01;今天来给大家推荐一款“短笛”拿铁&#xff0c;最近的最爱&#xff01;什么是短笛拿铁&#xff1f;piccolo latte&#xff0c;在意大利文中“piccolo”是小的意思&#xff0c;而latte则…

SQL Server 2016 RC0 安装(超多图)

微软最新版本的数据库SQL Server 2016在2016年3月9日推出了RC0版本。已经提供了包括简体中文等多种语言版本&#xff0c;不过联机丛书还是英文版的。对OS的要求是WIN8&#xff0c;WIN10&#xff0c; WIN2012&#xff0c;只有64位版本。让我们下载最新的版本安装测试下。Figure-…

vfp赋值超过7位出错_JDK1.7下的HashMap的源码分析

源码分析jdk1.7下的HashMap我们都知道1.7版本的hashmap的底层是数组加链表构成的&#xff0c;那么今天我们就来自己分析一波源码~篇幅有点长&#xff0c;废话不多说&#xff0c;直接开始分析~「属性声明」//初始化容量 static final int DEFAULT_INITIAL_CAPACITY 1 <4;…

笔记本打开计算机盘非常慢,笔记本开机慢怎么办【方法步骤】

许多人多余学术研究或是体育项目之类是十分精通&#xff0c;白手起家&#xff0c;闯出一片事业的也不在少数&#xff0c;但是在面对 高科 技产品时确实碰到了一鼻子灰&#xff0c;确实&#xff0c;各位读者朋友们所精通专业不同&#xff0c;在加上原本科技产品就是一大难题&…

Vi Notes

2019独角兽企业重金招聘Python工程师标准>>> 进入vi的命令 vi filename :打开或新建文件&#xff0c;并将光标置于第一行首 vi n filename &#xff1a;打开文件&#xff0c;并将光标置于第n行首 vi filename &#xff1a;打开文件&#xff0c;并将光标置于最后一行…

究极日月服务器维护时间,超激斗梦境9月25日终极测试服务器维护公告_超激斗梦境9月25日更新了什么_玩游戏网...

2021LPL夏季赛FPX vs V5第三场比赛视频2021LPL夏季赛8月4日FPXvsV5视频在哪看&#xff0c;比赛中FPXvsV5比赛中MVP又是谁&#xff0c;2021LPL夏季赛8月4日的比赛中FPXvsV5谁会获胜呢下面一起和小编来看看吧。【2021LPL夏季赛赛程】【2021LPL夏季赛直播】比赛时间&#xff1a;8月…

页面中用到iframe不能完全显示的解决方案

页面中用到iframe不能完全显示的解决方案 如果在页面中用到了iframe标签&#xff0c;有时在浏览器中并不能完全显示iframe&#xff0c;导致有些iframe内的内容不能被显示&#xff0c;如果遇到这种情况&#xff0c;使用以下js可以解决大多数问题。 这是iframe标签&#xff1a; &…

关灯看视频(Turn Off the Lights)

插件介绍随着使用互联网的人越来越多在网络上看视频已是常事一些相关的软件就运应而生今天为大家推荐一个能够提高用户们看视频体验的插件。关灯看视频Turn Off the Lights观看视频时自动调暗页面让您仿佛置身于电影院中只要轻轻按下灯的开关页面就会暗淡下去。 然后您就可以专…

seo 伪原创_如何判断外包的seo文章是否是抄袭或伪原创?

做为资深的外贸seo运营人员&#xff0c;应该会有将内容外包的情况。有时候就会遇到外包的人有抄袭、复制、伪原创的情况发生。那如何避免这种情况的出现呢&#xff1f;相信很多人都遇到过这种情况&#xff0c;是比较头疼的。那就需要检查。抄袭、伪原创这种是必须检查的&#x…

Interview and paper based test

笔试面试总结 榜样&#xff1a; http://www.cnblogs.com/figure9/archive/2013/01/09/2853649.html ArrayList和Vector的区别&#xff1f; http://blog.csdn.net/luxiaoxun/article/details/7980618 1. 输出集合的排列、组合 http://blog.csdn.net/u010570643/article/details/…

悲观锁和乐观锁_悲观锁和乐观锁处理并发操作

本人在金融公司任职,今天来分享下关于转账的一些并发处理问题,这节内容,我们不聊实现原来,就单纯的看看如何实现废话不多说,咱们直接开始,首先我会模拟一张转账表如下图所示:image.png一张简单的账户表,有name,账户余额等等,接下来我将用三种锁的方式来实现下并发下的互相转账一…

冰原服务器维护,怪猎OL9月20日0:00全区全服维护更新公告

亲爱的猎人&#xff1a;我们将于9月20日0:00对所有大区全部服务器进行更新维护&#xff0c;本次维护预计时间4小时。还请猎人们提早下线&#xff0c;避免不必要的损失。我们将视实际情况提前或延迟开服&#xff0c;感谢大家的支持!维护时间&#xff1a;2016年9月20日(周二)0:00…

属性类:Properties

在一个属性文件中保存了多个属性&#xff0c;每一个属性就是直接用字符串表示出来的"keyvalue对"&#xff0c;而如果想要轻松地操作这些属性文件中的属性&#xff0c;可以通过Properties类方便地完成。 <1>设置和取得属性 import java.util.Properties;// // F…

Js操作cookie

为什么80%的码农都做不了架构师&#xff1f;>>> 贴上一段js操作cookie的方法&#xff1a; //setCookie function setCookie(cname, cvalue, exdays) { var d new Date(); d.setTime(d.getTime() (exdays*24*60*60*1000)); //day var expires "expires…

Eclipse3.6.2 64位启动报“Failed to load the JNI shared library”错的解决方法

Eclipse3.6.2 64位解压后双击运行eclipse&#xff0c;报“Failed to load the JNI shared library”错误。 如下图所示&#xff1a; 原来我的jdk是以前旧32位系统安装jdk后&#xff0c;不支持Eclipse3.6.2 64位导致报错&#xff0c;无法正常运行。从官网上&#xff1a; http://…

一个长方体玻璃容器从里面量长宽_泰来包装分享:如何设计钢边箱里面中型木包装箱...

钢边箱里面的中型木包装箱是以木质材料为主制成的有一定刚性的包装容器&#xff0c;是产品运输包装的主要容器之一&#xff0c;也是我国出口商品使用非常广泛的一种包装&#xff0c;在轻工&#xff0c;机械&#xff0c;半导体等包装领域起着不可替代的重要作用。关于钢边箱里面…

uml 中的小人

平常画uml的时候&#xff0c;经常会用到Actor, 也没仔细思考过Actor的深刻内涵今天看了程序员11月的杂志&#xff0c;里面有篇文章叫<这个小人不简单>&#xff0c;文章中强调用例技术的不同之处在于发现了"卖"-需求是研究软件怎么好卖的技能。现在对uml有了更深…