题目:打开一个文本文件,每次读取一行内容,将每行作为一个String读入,并将那个String对象置入一个LinkedList中,按照相反的顺序打印出LinkedList中的所有行.

解题代码:

 public static List<String> read(String filename) throws Exception {
String filepath = "path";
FileReader fileReader = new FileReader(filepath + filename);
BufferedReader in = new BufferedReader(fileReader);
List<String> list = new LinkedList<String>();
String s;
while((s = in.readLine()) != null)
list.add(s + "\n");
in.close();
return list;
}
public static void main(String[] args) throws Exception{
List<String> list = read("filename");
for(ListIterator<String> it = list.listIterator(list.size()); it.hasPrevious();)
System.out.print(it.previous());
}
题目中:将那个String对象置入一个LinkedList中,按照相反的顺序打印出LinkedList中的所有行.对应代码时
for(ListIterator<String> it = list.listIterator(list.size()); it.hasPrevious();)
System.out.print(it.previous());
通过调用LinkedList的listIterator(),返回一个指向链表最后一个元素的指针,在从后向前遍历.
先看一下ListIterator接口的定义:
 public interface ListIterator<E> extends Iterator<E> {
//Iteator接口定义的方法.
boolean hasNext();
E next();
void remove(); boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void set(E e);
void add(E e);
}

在看一下LinkedList类中对ListIterator接口的实现:

 private class ListItr implements ListIterator<E> {
//lastReturned为最近返回的节点,当调用previous()时,lastReturned = next;
private Node<E> lastReturned;
//next为当前节点的下一个节点.
private Node<E> next;
//nextIndex的范围是0-(size-1)(链表的长度减一).表示下个节点在链表中的位置.
private int nextIndex;
private int expectedModCount =modCount; ListItr(int index) {
/*
*如果index等于size,则表示要跳转到链表的末端,则next=null,否则调用node(index).
*nextIndex被赋值为index.
*/
next = (index == size) ? null : node(index);
nextIndex = index;
}
//nextIndex的合理范围在0-(size-1)
public boolean hasNext() {
return nextIndex < size;
} public E next() {
checkForComodification();
//判断是否有下一个值.
if(!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
//nextIndex的范围在0-(size-1),所以只要nextIndex>0,就表示当前节点有前节点.
public boolean hasPrevious() {
return nextIndex > 0;
}
//当调用previous时,lastReturned等于next.
public E previous() {
checkForComodification();
if(!hasPrevious())
throw new NoSuchElementException();
将lastReturned = next.
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
} public int nextIndex() {
return nextIndex;
} public int previousIndex() {
return nextIndex - 1;
}
//remove()移除的是lastReturned节点.
public void remove() {
checkForComodification();
if(lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
//移除lastReturned
/*
*首先要考虑如果要删除的是链表中的第一个/最后一个节点.
*按照正常情况:
*lastReturned.prev.next = lastReturned.next;
*lastReturned.next.prev = lastReturned.prev;
*lastReturned.next,lastReturned.prev,lastReturned.item设置为null;
*链表长度减一.
*/
unlink(lastReturned);
if(next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
} public void set(E e) {
if(lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
//向链表中添加节点.
public void add(E e) {
checkForComodification();
lastReturned = null;
//如果next==null,表示要插入到链表的末端.
if(next == null)
linkLast(e);
//否则插入到链表
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
} final void checkForComodification() {
if(modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
//采用二分法的形式,跳转的链表中第index个节点.
Node<E> node(int index) {
// assert isElementIndex(index);
//size >> 1 表示size/2
if (index < (size >> 1)) {
//first是链表的第一个节点
Node<E> x = first;
//从前向后查找
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//last是链表的最后一个节点.
//从后向前查找.
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
//
E unlink(Node<E> x) {
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
//如果要删除的是第一个元素,则x.prev == null;需要将链表中的第一个节点first标记为next.
if(prev == null)
first = next;
//否则按照正常逻辑x.prev.next = x.next.在将当前节点的prev设置为null.
else {
prev.next = next;
x.prev = null;
}
//如果要删除的是最后一个元素,则x.next== null;需要将链表中最后一个几点last标记为prev.
if(next == null)
last = prev;
//否则按照正常逻辑x.next.prev = x.prev.将当前节点的next设置为null.
else {
next.prev = prev;
x.next = null;
}
//将当前节点的item设置为null.
x.item = null;
//链表长度减一.
size--;
//修改次数加一.
modCount++;
return element;
}
/*
*向链表的末端添加节点.这里需要考虑如果链表为空,链表不为空.
*要写出优秀的代码,要将链表为空和不为空都执行的部分提取出来,之后在考虑不一样的情况.
*/
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<E>(l, e, null);
last = node;
//l == null 的话,表示链表为空.将first设置为newNode
if(l == null)
first = newNode;
//如果链表不为空,将原来链表的最后一个节点.next = newNode.
else
l.next = newNode;
size++;
modCount++;
}
/*在succ节点前,添加节点.要考虑succ是不是头节点.
*
*/
void linkBefore(E e, Node<E> succ) {
final Node<E> pred = succ.prev;
Node<E> newNode = new Node<E>(pred, e, succ);
succ.prev = newNode;
//如果succ是头节点,则pred = succ.prev == null.将头节点设置为newNode
if(pred == null)
first = newNode;
else
prev.next = newNode;
size++;
modCount++;
}
 

一道题引出对LinkedList源码的研究的更多相关文章

  1. 给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析

    LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明.   1.链表的概念      链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链 ...

  2. LinkedList源码解析

    LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明.1.链表的概念链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链表又分为单向链表和 ...

  3. LinkedList源码解读

    一.内部类Node数据结构 在讲解LinkedList源码之前,首先我们需要了解一个内部类.内部类Node来表示集合中的节点,元素的值赋值给item属性,节点的next属性指向下一个节点,节点的pre ...

  4. ArrayList和LinkedList源码

    1 ArrayList 1.1 父类 java.lang.Object 继承者 java.util.AbstractCollection<E> 继承者 java.util.Abstract ...

  5. 转:【Java集合源码剖析】LinkedList源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/35787253   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票 ...

  6. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  7. LinkedList源码和并发问题分析

    1.LinkedList源码分析 LinkedList的是基于链表实现的java集合类,通过index插入到指定位置的时候使用LinkedList效率要比ArrayList高,以下源码分析是基于JDK ...

  8. ArrayList 和 LinkedList 源码分析

    List 表示的就是线性表,是具有相同特性的数据元素的有限序列.它主要有两种存储结构,顺序存储和链式存储,分别对应着 ArrayList 和 LinkedList 的实现,接下来以 jdk7 代码为例 ...

  9. Android版数据结构与算法(三):基于链表的实现LinkedList源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. LinkedList 是一个双向链表.它可以被当作堆栈.队列或双端队列进行操作.LinkedList相对于ArrayList来说,添加,删除元素效 ...

随机推荐

  1. springcolud文章收藏

    https://blog.csdn.net/dyc87112/column/info/14412https://blog.csdn.net/dyc87112/article/details/79357 ...

  2. Vue实现跑马灯的效果

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. Java上传和下载

    1.文件的上传 [1] 简介 > 将一个客户端的本地的文件发送到服务器中保存. > 上传文件是通过流的形式将文件发送给服务器. [2] 表单的设置 > 向服务器上传一个文件时,表单要 ...

  4. 【Mybatis】MyBatis之Sql配置文件的使用(四)

    上一章[Mybatis]MyBatis对表执行CRUD操作(三),已经讲了基本操作,本章介绍Sql配置文件中常用功能 1.插入返回主键 2.参数值的获取方式 3.resultMap使用 插入返回主键 ...

  5. safari10.0以上版本出现默认小人头图标

    1.可能改input输入框外层有兄弟元素在input之前,将input元素位置放置在所有兄弟元素之前即可

  6. JAVA 8 日期工具类

    JAVA 8 日期工具类 主题描述 JAVA中日期时间的历史 代码成果 主题描述 JAVA的日期时间一直比较混乱,本来以为joda会是巅峰,但是JAVA 8改变了我的思想.但是即便在JAVA 8面前, ...

  7. 一. IntelliJ IDEA详细配置文档之初始环境搭建

    前言 对于用惯了eclipse的同学来说, 突然切换为idea不是一件那么容易的事情, 所以我会发布一系列只讲解idea使用技巧的文章, 请大家多多关注.  本系列文章的配置参考网上某教程的讲解, 本 ...

  8. CodeSampler DX9 Full-screen initialization

    D3D新手,请轻拍. 最近在学CodeSampler上的DX9范例.编译环境是VS2012.搭编译环境用了一两天,另行开文吐槽(有时间的话). 本文讲讲Full-screen initializati ...

  9. 将preg_replace()改写为preg_replace_callback()

    preg_replace()函数使用/e修饰符可能带来安全隐患,PHP5.5之后,该用法被抛弃使用,升级为preg_replace_callback().在新版本下运行老版本的代码,会出现错误,如: ...

  10. 关于n维和n-1维欧式空间

    我们从小就说,"点动成线,线动成面,面动成体",其中的空间的概念到底是啥?之前没有好好想过,在机器学习中多次遇到"空间"."超平面",&qu ...