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,一经查实,立即删除!

相关文章

3013-04-13 腾讯笔试

题目及答案参考&#xff1a;地址 为什么腾讯笔试的时间是10:30到12:30?难道腾讯人事部认为计算机的学生都是3点睡觉&#xff0c;9点起床&#xff0c;13点吃饭的吗&#xff1f;做了半个小时的题&#xff0c;就饿了&#xff1b;而且刚开始发卷子的时候&#xff0c;那卷子的模样&…

jquery调用asp.net 页面后台方法

先创建一个aspx页面编写一个客户端控件<input type"button" id"AjaxDemo" value"AjaxDemo"> 再aspx后台的页面编写一个简单的方法,代码如下: [WebMethod]public static string ABC(string ABC){ return ABC;} 必须声明为静态方法&#…

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

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

江西计算机一级考试教程,江西省2019年下半年计算机一级考试复习教程:计算机基础及MS Office应用上机指导...

&nbsp&nbsp[导读]:江西省2019年下半年计算机一级考试复习教程&#xff1a;计算机基础及MS Office应用上机指导&#xff0c;更多江西等级考试用书&#xff0c;请访问易考吧江西等级考试栏目江西省2019年下半年计算机一级考试复习教程&#xff1a;计算机基础及MS Office应…

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则…

计算机发展趋势是规格化,2016年春季计算机应用基础月考卷(4月).doc

2016年春季学期计算机应用基础4月考卷姓名&#xff1a; 得分&#xff1a;一、单项选择题。(共有75个小题&#xff0c;每小题2分&#xff0c;共计150分)1. 计算机的发展通常认为经历了四代&#xff0c;第二代计算机的主要元器件是( )A. 电子管 B&#xff0e;晶体管 C&#xff0e…

C#与.NET程序员面试宝典 1.3 投递简历

在IT行业中&#xff0c;应聘是大多数人获得工作机会的主要途径&#xff0c;通常人们从学校毕业后即开始参加各种形式的招聘场合。从招聘方的角度来说&#xff0c;不同的公司有不同的招聘渠道&#xff0c;但大多数都会重点采用网络、校园、招聘会3个渠道进行招聘员工。想要应聘到…

回归初心

软件工程这门课程已经上了两周了&#xff0c;可以说这两周过得非常的充实&#xff0c;除了上课时间&#xff0c;其余的课余时间都用来写作业和看书了。我想&#xff0c;这才是刚进入大学时&#xff0c;我憧憬的生活。现在看来&#xff0c;过去的三年确实会感到有点遗憾&#xf…

scipy是python下的什么_Python下科学计算包numpy和SciPy的安装

Python下大多数工具包的安装都很简单&#xff0c;只需要执行 “python setup.py install”命令即可。然而&#xff0c;由于SciPy和numpy这两个科学计算包的依赖关系较多&#xff0c;安装过程较为复杂。网上教程较为混乱&#xff0c;而且照着做基本都不能用。在仔细研读各个包里…

计算机指令格式哪几部分组成,计算机的指令格式,通常是由()两部分组成。 - 百科题库网...

1.8086汇编语言指令由标号、操作码、操作数和注释组成,其中标号和注释可以省略&#xff0c;操作码指出指令要过盛的功能,操作数指出完成的对象. 2.变量和标号的区别是变量由伪指令定义&#xff0c;标号是指令前面的符号&#xff0c;变量也伪指令定义符之间由空格分隔&#xff0…

执行phpinfo();时提示:date_default_timezone_set()

执行phpinfo();时提示&#xff1a; Warning: phpinfo() [function.phpinfo]: It is not safe to rely on the systems timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those …

nlog轻量级日志组件

一.NLog简要介绍: 1.NLog是一个简单灵活的.NET日志记录类库。通过使用NLog&#xff0c;我们可以在任何一种.NET语言中输出带有上下文的&#xff08;contextual information&#xff09;调试诊断信息&#xff0c;根据喜好配置其表现样式之…

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;…

计算机常用数制转换说课稿,进制与进制转换说课稿

《数制及其转换》 尊敬的各位老师&#xff1a;大家好&#xff01;我说课的内容是《数制及其转换》。一、说教材1、教材分析《数制及其转换》是从人民邮电出版社教材《大学计算机基础》第一章第三节内容&#xff0c;它是理解计算机原理的重要突破点&#xff0c;奠定了学生对计算…

java.net.SocketException: Permission denied解决

该文引自&#xff1a;http://hi.baidu.com/sunfengwei/item/6c4c8b68d015ea2569105bc2 在Android项目开发时&#xff0c;在获取IP地址时出现java.net.SocketException: Permission denied异常&#xff0c;这是一个典型的异常。 解决方法&#xff1a; 在AndroidManifest.xml 配置…

Android代码优化——使用Android lint工具

Android代码优化——使用Android lint工具

【转】wordpress/wp-includes目录文件概述

wp-includes目录1.wp-includes/cache.php2.wp-includes/capabilities.php3.wp-includes/class-IXR.php&#xff1a;Incutio XML-RPC库。包括了 XML RPC支持函数。由http://scripts.incutio.com/xmlrpc/提供支持。4.wp-includes/classes.php&#xff1a;包括了基本的类&#xff…