题目:打开一个文本文件,每次读取一行内容,将每行作为一个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. Sum of Subsequence Widths LT891

    Given an array of integers A, consider all non-empty subsequences of A. For any sequence S, let the  ...

  2. hbase_存储模型

    Hbase 是按列存储,所以每个列族存储在一个HDFS文件上. Hbase表中的行是按照rowkey字典序进行排列的,并且表格在行的方向上被分割为多个region(按照行进行分割的) region 是 ...

  3. SVG制作可爱小页面

    很久都没有在博客园上发表一些自己学的新东西了,只是在有空的时候逛一逛博客园而已,看来我不是一个真正的程序员,哈哈! 但是今天非常想和大家分享一个小东西,那是前两天在一个网页上看到了这个东西 我好奇中间 ...

  4. 《Linux就该这么学》第十八天课程

    1.使用MariaDB数据库管理系统 今天没什么笔记,就不发了.想深入学习的可以前往原创地址:https://www.linuxprobe.com/chapter-18.html 图18-1 Mari ...

  5. android各种笔记

    一.生成key http://blog.csdn.net/anyanyan07/article/details/53493785 二.mac os项目变大 删除 项目中app->build文件夹 ...

  6. Unity中AB资源打包简单的脚本

    脚本应该放在Editor文件夹下 using System.Collections; using System.Collections.Generic; using UnityEngine; usin ...

  7. Codeforces Round #485 (Div. 2) D. Fair

    Codeforces Round #485 (Div. 2) D. Fair 题目连接: http://codeforces.com/contest/987/problem/D Description ...

  8. 洛谷P1746 离开中山路

    https://www.luogu.org/problemnew/show/P1746 思路:用广搜从起点开始,遍历所有可达的点,再往下遍历直到到达终点,所以能保证得到的结果一定是最优解 #inclu ...

  9. U-Boot Makefile分析(3) rules.mk分析

    浏览各个子Makefile可以发现,他们都会在文件的后面包含rules.mk,这个文件的作用就是更新源文件的依赖,并生成各种.depend文件. _depend: $(obj).depend # Sp ...

  10. JS 控制输入框输入表情emoji 显示在页面上

    问题描述: 最近做一个评论回复的功能遇到了用户输入框输入表情,存入数据库的时候转变成了问号??? 起初为了避免这个问题,做了一个过滤表情的控制 var inputText = $('#pinglun' ...