您的位置:首页 > 编程语言 > Java开发

Java集合系列05 之LinkedList详细介绍

2018-02-01 15:06 435 查看

概要

本篇博客我们将继续学习集合框架。这一篇我们接着学习Lis的实现类—LinkedList。

主要内容

LinkedList介绍

Queue 介绍

Deque介绍

LinkedList数据结构

LinkedList源码分析

LinkedList遍历方式

LinkedList使用示例

1. LinkedList介绍

LinkedList是一个继承于AbstractSequentialList双向链表。他可以被当做堆栈、队列和双端队列来使用。

LinkedList实现了List接口,能对他进行队列操作。这个是因为。在LinkedList的默认实现时就是按照队列实现的。具体的看后面

LinkedList是吸纳Deque接口,能对他进行双端队列操作。

LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。

LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。

LinkedList 是非同步的。

2. queue介绍

这也可能是在java.util下面的集合框架中为数不多能用到queue接口的地点。实际上LinkedList本身没有实现queue,而是实现了Deque,而Deque继承了queue接口。

Queue接口定义如下

public interface Queue<E> extends Collection<E> {
}


Queue继承了Collection接口,因此Collection接口有的方法,queue都有,不过有下面一些是Queue自己特有的,都是为绕着队列来实现的。

queue定义的API如下:

public abstract boolean add(E e) 在队列末尾插入元素
public abstract E element()  得到队列头部节点元素
public abstract boolean offer(E e) 插入节点到集合尾部
public abstract E peek()     返回集合头部节点
public abstract E poll()     返回并删除集合头部节点
public abstract E remove()   返回并删除集合头部节点


上面六个方法,总结如下

操作不成功时抛出异常的方法返回特定值得方法
Insertadd(e)offer(e)
Removeremove()poll()
Examineelement()peek()

3. Deque介绍

Deque是double ended queue的简写,就是双端队列的意思。可以在队列俩端进行操作。

接口的定义如下

public interface Deque<E> extends Queue<E> {

}


Deque接口自己独有的方法如下。

public abstract void addFirst(E e);  // 在队列的头部插入元素节点
public abstract void addLast(E e)    // 在队列的尾部插入元素
public abstract boolean offerFitrst(E e)// 在队列头部插入元素
public abstract boolean offerLast(E e); //在队列的尾部插入元素
public abstract E removeFirst();        //删除头部节点并返回元素
public abstract E removeLast();        //删尾部节点并返回元素
public abstract E pollFirst();       //删除并返回头部节点元素
public abstract E pollLast();        //删除并返回尾部节点元素
public abstract E getFirst();        //得到头部节点元素但不删除
public abstract E getLast();         //得到尾部节点元素但不删除
public abstract E peekFirst();        //得到头部节点元素但不删除
public abstract E peekLast();         //得到尾部节点元素但不删除
public abstract boolean removeFirstOccurrence(Object o); //检索第一个相等元素并返回
public abstract boolean removeLastOccurrence(Object o); //检索最后一个相等元素并返回

//stack 方法
public abstract void push(E e)     //插入节点到此队列代表的栈头
public abstract  E pop();          //删除并返回头部节点

//集合方法
boolean remove(Object o);
boolean contains(Object o);
public int size();
Iterator<E> iterator();
Iterator<E> descendingIterator();


对以上方法进行总结

操作类型First Element (Head)Last Element (Tail)
是否抛出异常Throws exceptionSpecial valueThrows exceptionSpecial value
InsertaddFirst(e)offerFirst(e)addLast(e)offerLast(e)
RemoveremoveFirst()pollFirst()removeLast()pollLast()
ExaminegetFirst()peekFirst()getLast()peekLast()
但是我在阅读源代码的时候,没有发addFrist抛出异常的代码,希望大家能指出一下

queue和Deque之间的对比

Queue MethodEquivalent Deque Method
add(e)addLast(e)
offer(e)offerLast(e)
remove()removeFirst()
poll()pollFirst()
element()getFirst()
peek()peekFirst()
对比stack和Deque方法

Stack MethodEquivalent Deque Method
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()
通过以上对比,应该对queue和Dqueue有一个大体上的了解,写上面的内容只是为了熟悉一下方法,方便自己以后使用。也对整体有个了解。

4. LinkedList数据结构

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 {}


LinkedList的类图如下



LinkedList本质是双向链表

LinkedList包含三个比较重要的成员:first、last和size

first指向双向链表的表头。

last指向双向链表的尾部。

size是双向链表中节点的个数。

5. LinkedList源码分析

源码如下,由于后面有一部分是java8流需要用到的知识,在这里就不去讲。

package java.util;

import java.util.function.Consumer;

public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {

//链表的长度
transient int size = 0;

/**
* 指向链表的第一个节点
*      初始化时定义如下:
*            (first == null && last == null) ||
*            (first.prev == null && first.item != null)
*/
transient Node<E> first;

/**
* 指向链表的最后一个节点
*          初始化时定义如下:
*            (first == null &&
*            (last.next == null && last.item != null)
*/
transient Node<E> last;

public LinkedList() {
}

//初始化链表,包含指定集合元素
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}

//把元素插入到链表的头部
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}

//把元素插入到链表的尾部
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++;
}

//在一个非空节点之前插入元素
void linkBefore(E e, Node<E> succ) {

final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}

//删除List的第一个非空节点
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}

//删除List的最后一个非空节点
private E unlinkLast(Node<E> l) {

final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}

//删除一个非空节点
E unlink(Node<E> x) {

final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;

if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}

if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}

x.item = null;
size--;
modCount++;
return element;
}

//得到第一个元素
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}

//返回最后一个元素
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}

//删除并返回第一个元素
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}

//删除并返回最后一个元素
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}

//插入元素到第一个位置
public void addFirst(E e) {
linkFirst(e);
}

//添加元素到最后一个位置
public void addLast(E e) {
linkLast(e);
}

//判断集合中是否包含指定的元素
public boolean contains(Object o) {
return indexOf(o) != -1;
}

//返回刺激和的大小
public int size() {
return size;
}

//添加元素到集合末尾
public boolean add(E e) {
linkLast(e);
return true;
}

//移除和指定元素相等的集合元素,如果包含多个,也是只删除一个
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}

//添加集合c到此集合的末尾
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}

//从指定位置开始插入集合c到此集合末尾
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index); //检查插入位置是否合适

Object[] a = c.toArray(); //得到此集合对应的数组
int numNew = a.length;
if (numNew == 0) //判断集合是否为空
return false;

Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}

//将插入的集合c连接成链表
for (Object o : a) {
@SuppressWarnings("unchecked")
E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
//将插进来的集合链接到此集合上
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}

size += numNew;
modCount++;
return true;
}

//删除所有的元素
public void clear() {
for (Node<E> x = first; x != null;) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}

// 在指定位置进行操作

//返回指定位置的元素
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}

//在指定的位置替换元素,并返回旧值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}

//在指定的位置插入元素
public void add(int index, E element) {
checkPositionIndex(index);

if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}

//删除指定位置的元素
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}

//判断当前位置是否存在元素
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}

//告诉迭代器或者插入操作,当前位置是否可以进行操作
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}

//创建抛出超出索引异常的模板信息
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}

//检查索引是否存在元素
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

//检查当前位置是否可以操作
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

//返回非空指定索引位置的节点
Node<E> node(int 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;
}
}

//查询操作

//返回和查找元素匹配的第一个存在的元素的索引
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}

//返回和查找元素匹配的最后一个存在的元素的索引
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}

// 队列操作

//返回头结点,但不删除
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}

//返回头结点,但不删除
public E element() {
return getFirst();
}

//返回头结点并移除
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}

//删除头结点并返回
public E remove() {
return removeFirst();
}

//添加指定元素在集合末尾
public boolean offer(E e) {
return add(e);
}

// 双端队列操作

//在集合头部插入元素
public boolean offerFirst(E e) {
addFirst(e);
return true;
}

//在集合尾部插入元素
public boolean offerLast(E e) {
addLast(e);
return true;
}

//得到集合第一个元素
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}

//得到集合最后一个元素但不删除
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}

//得到并移除第一个元素
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}

//得到并移除最后一个元素
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}

//在集合头部插入元素
public void push(E e) {
addFirst(e);
}

//得到并删除第一个元素 ,如果为空抛出异常
public E pop() {
return removeFirst();
}

//删除第一个和o对象相等的元素
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}

//删除最后一个和o对象相等的元素
public boolean removeLastOccurrence(Object o) {
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}

//返回冲指定位置开始的listIterator 抛出异常
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}

// 实现ListIterator接口
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned; //上一次返回的索引
private Node<E> next; //后继指针
private int nextIndex; //指向的索引
private int expectedModCount = modCount; //当前遍历时,List的大小

//根据指定的索引位置 创建ListIterator对象
//即next指向当前索引的对象
ListItr(int index) {

next = (index == size) ? null : node(index);
nextIndex = index;
}

//判断当前索引是否小于List的长度
public boolean hasNext() {
return nextIndex < size;
}

//返回当前元素
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();

lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}

//判断当前节点是否有还有前继节点
public boolean hasPrevious() {
return nextIndex > 0;
}

//返回当前节点的前继节点
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();

lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}

//返回后继节点的索引
public int nextIndex() {
return nextIndex;
}

//返回前继节点的索引
public int previousIndex() {
return nextIndex - 1;
}

//移除当前元素
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();

Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++; //++的原因是:在List中每一次改变集合的操作,都会是modCount加一,这些操作包括修改,删除,添加
}

//替换当前元素
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}

//在末尾添加元素
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}

public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}

final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

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

//逆序返回ListIterator
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}

//实现逆序返回Iterator
private class DescendingIterator implements Iterator<E> {
private final ListItr itr = new ListItr(size());

public boolean hasNext() {
return itr.hasPrevious();
}

public E next() {
return itr.previous();
}

public void remove() {
itr.remove();
}
}

@SuppressWarnings("unchecked")
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}

//返回一个浅拷贝LinkedList对象
public Object clone() {
LinkedList<E> clone = superClone();

// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;

// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);

return clone;
}

public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;

if (a.length > size)
a[size] = null;

return a;
}

private static final long serialVersionUID = 876323262645176354L;

//序列化对象
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject();

// Write out size
s.writeInt(size);

// Write out all elements in the proper order.
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
}

//反序列化对象
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();

// Read in size
int size = s.readInt();

// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
linkLast((E) s.readObject());
}

//这个是java8 新加的一个特性,用于并行流使用时怎么划分集合
@Override
public Spliterator<E> spliterator() {
return new LLSpliterator<E>(this, -1, 0);
}

//构造java8 的并行化流时进行划分集合使用的方法
static final class LLSpliterator<E> implements Spliterator<E> {
static final int BATCH_UNIT = 1 << 10; // batch array size increment
static final int MAX_BATCH = 1 << 25; // max batch array size;
final LinkedList<E> list; // null OK unless traversed
Node<E> current; // current node; null until initialized
int est; // size estimate; -1 until first needed
int expectedModCount; // initialized when est set
int batch; // batch size for splits

LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
this.list = list;
this.est = est;
this.expectedModCount = expectedModCount;
}

final int getEst() {
int s; // force initialization
final LinkedList<E> lst;
if ((s = est) < 0) {
if ((lst = list) == null)
s = est = 0;
else {
expectedModCount = lst.modCount;
current = lst.first;
s = est = lst.size;
}
}
return s;
}

public long estimateSize() {
return (long) getEst();
}

public Spliterator<E> trySplit() {
Node<E> p;
int s = getEst();
if (s > 1 && (p = current) != null) {
int n = batch + BATCH_UNIT;
if (n > s)
n = s;
if (n > MAX_BATCH)
n = MAX_BATCH;
Object[] a = new Object
;
int j = 0;
do {
a[j++] = p.item;
} while ((p = p.next) != null && j < n);
current = p;
batch = j;
est = s - j;
return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
}
return null;
}

public void forEachRemaining(Consumer<? super E> action) {
Node<E> p;
int n;
if (action == null)
throw new NullPointerException();
if ((n = getEst()) > 0 && (p = current) != null) {
current = null;
est = 0;
do {
E e = p.item;
p = p.next;
action.accept(e);
} while (p != null && --n > 0);
}
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
}

public boolean tryAdvance(Consumer<? super E> action) {
Node<E> p;
if (action == null)
throw new NullPointerException();
if (getEst() > 0 && (p = current) != null) {
--est;
E e = p.item;
current = p.next;
action.accept(e);
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
return false;
}

public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}

}


总结:

LinkedList实际上是通过双向链表实现。它包含了一个内部类Node,用于封装节点信息。

由于使用的链表,所以不会存在容量不足的问题。

LinkedList的克隆函数,是将全部元素克隆到一个新的LinkedList对象中。不过集合中的对象有可能指向的是相同的地址。

LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

LinkedList遍历方式

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

(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

for(Iterator iter = list.iterator(); iter.hasNext();)
iter.next();


(02) 通过快速随机访问遍历LinkedList

int size = list.size();
for (int i=0; i<size; i++) {
list.get(i);
}


(03) 通过另外一种for循环来遍历LinkedList

for (Integer integ:list)
;


(04) 通过pollFirst()来遍历LinkedList

while(list.pollFirst() != null)
;


(05) 通过pollLast()来遍历LinkedList

while(list.pollLast() != null)
;


(06) 通过removeFirst()来遍历LinkedList

try {
while(list.removeFirst() != null)
;
} catch (NoSuchElementException e) {
}


(07) 通过removeLast()来遍历LinkedList

try {
while(list.removeLast() != null)
;
} catch (NoSuchElementException e) {
}


测试代码

import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;

/**************************************
*      Author : zhangke
*      Date   : 2018/1/31 19:05
*      Desc   : 比较不同遍历类型的时间开销
***************************************/
public class LinkedListVisit {

public static void main(String[] args) {
//通过迭代器遍历
iteratorLinkedListThruIterator(getLinkedList());

//通过随机访问遍历
iteratorLinkedListThruRan(getLinkedList());

//通过foreach遍历
iteratorLinkedListThruForeach(getLinkedList());

//通过revmoveFirst遍历
iteratorLinkedListThruRemoveFirst(getLinkedList());

//通过removeLast遍历
iteratorLinkedListThruRemoveLast(getLinkedList());

//通过pollFirst遍历
iteratorLinkedListThruPollFirst(getLinkedList());

//通过pollLast遍历
iteratorLinkedListThruPollLast(getLinkedList());
}

/**
* 创建一个LinkedList包含 10000个元素
*
* @return
*/
private static LinkedList getLinkedList() {
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 10000; i++) {
list.add(i);
}
return list;
}

/**
* 通过迭代器遍历LinkedList
*/
private static void iteratorLinkedListThruIterator(LinkedList<Integer> list) {
if (list == null)
return;

//记录开始时间
long start = System.currentTimeMillis();
for (Iterator iter = list.iterator(); iter.hasNext(); )
iter.next();

//记录结束时间
long end = System.currentTimeMillis();
System.out.println("iteratorLinkedListThruIterator:" + (end - start));
}

/**
* 通过随机访问遍历LinkedList
*/
private static void iteratorLinkedListThruRan(LinkedList<Integer> list) {
if (list == null)
return;

//记录开始时间
long start = System.currentTimeMillis();
for (int n = list.size(), i = 0; i < n; i++)
list.get(i);
//记录结束时间
long end = System.currentTimeMillis();
System.out.println("iteratorLinkedListThruRan:" + (end - start));
}

/**
* 通过foreach来遍历LinkedList
*/
private static void iteratorLinkedListThruForeach(LinkedList<Integer> list) {
if (list == null)
return;

//记录开始时间
long start = System.currentTimeMillis();
for (Integer e : list)
;
//记录结束时间
long end = System.currentTimeMillis();
System.out.println("iteratorLinkedListThruForeach:" + (end - start));
}

/**
* 通过pollFirst来遍历LinkedList
*/
private static void iteratorLinkedListThruPollFirst(LinkedList<Integer> list) {
if (list == null)
return;

//记录开始时间
long start = System.currentTimeMillis();
while (list.pollLast() != null)
;
//记录结束时间
long end = System.currentTimeMillis();
System.out.println("iteratorLinkedListThruPollFisrst:" + (end - start));
}

/**
* 通过pollLast来遍历LinkedList
*/
private static void iteratorLinkedListThruPollLast(LinkedList<Integer> list) {
if (list == null)
return;

//记录开始时间
long start = System.currentTimeMillis();
while (list.pollLast() != null)
;
//记录结束时间
long end = System.currentTimeMillis();
System.out.println("iteratorLinkedListThruPollLast:" + (end - start));
}

/**
* 通过removeFirst来遍历LinkedList
*/
private static void iteratorLinkedListThruRemoveFirst(LinkedList<Integer> list) {
if (list == null)
return;

//记录开始时间
long start = System.currentTimeMillis();
try {
while (list.removeFirst() != null)
;
} catch (NoSuchElementException e) {
//处理链表中没有此元素
}

//记录结束时间
long end = System.currentTimeMillis();
System.out.println("iteratorLinkedListThruRemoveFirst:" + (end - start));
}

/**
* 通过removeFirst来遍历LinkedList
*/
private static void iteratorLinkedListThruRemoveLast(LinkedList<Integer> list) {
if (list == null)
return;

//记录开始时间
long start = System.currentTimeMillis();
try {
while (list.removeLast() != null)
;
} catch (NoSuchElementException e) {
//处理链表中没有此元素
}

//记录结束时间
long end = System.currentTimeMillis();
System.out.println("iteratorLinkedListThruRemoveLast:" + (end - start));
}
}


执行结果

iteratorLinkedListThruIterator:4
iteratorLinkedListThruRan:4854
iteratorLinkedListThruForeach:3
iteratorLinkedListThruRemoveFirst:2
iteratorLinkedListThruRemoveLast:1
iteratorLinkedListThruPollFisrst:1
iteratorLinkedListThruPollLast:1


我运行了很多次结果都会出现1的结果但是用纳秒又会使得数字很大,所以最后就用了上面的结果,遍历LinkedList,使用pollFirst或pollLast效率最高。但他们遍历时,则会删除原始数据;若是只读取,而不删除,应该使用foreach来遍历,而不是fori遍历。

6. 使用栈

package Collections.cnblog.collection.list;

import java.util.LinkedList;

/**************************************
*      Author : zhangke
*      Date   : 2018/2/1 10:26
*      Desc   : LinkedList API 简单使用
***************************************/
public class SimpleUseLinkedList {

public static void main(String[] args) {
testLinkedListAPIs();
useLinkedFIFO();
useLinkedListAsFIFO();
}

/**
* 简单使用LinkedList中部分API
*/
private static void testLinkedListAPIs() {
//新建一个LinkedList
LinkedList<String> list = new LinkedList<>();

//添加操作
list.add("1");
list.add("2");
list.add("3");

//将 4 添加到第一个位置
list.add(1, "4");
System.out.println("使用addFitst,removeFirst,getFirst");

//下面三个如果操作失败,则抛出异常

//将10 添加到第一个位置,失败的话,则抛出异常
list.addFirst("10");
System.out.println("list:" + list);

//将一个元素删除,失败的话,抛出异常
System.out.println("list.removeList" + list.removeFirst());

//获取第一个元素,失败的话,抛出异常
System.out.println("List.getFirst" + list.getFirst());

System.out.println("使用offerFirst,pollFirst,peekFirst");
//将10 添加到第一个位置,返回true
list.offerFirst("10");

System.out.println("list.offer" + list);

//将第一个元素删除,失败的话返回null
System.out.println("list.pollFirst" + list.pollFirst());
System.out.println("list:" + list);

//获取第一个元素,失败的话返回null
System.out.println("list.peekFirst" + list.peekFirst());

//下面三个添加元素到最后一个位置,失败的话,都会抛出异常
// (01) 将“20”添加到最后一个位置。  失败的话,抛出异常!
list.addLast("20");
System.out.println("llist:" + list);
// (02) 将最后一个元素删除。        失败的话,抛出异常!
System.out.println("llist.removeLast():" + list.removeLast());
System.out.println("llist:" + list);
// (03) 获取最后一个元素。          失败的话,抛出异常!
System.out.println("llist.getLast():" + list.getLast());

System.out.println("使用 offerLast(), pollLast(), peekLast()");
// (01) 将“20”添加到最后一个位置。  返回true。
list.offerLast("20");
System.out.println("llist:" + list);
// (02) 将最后一个元素删除。        失败的话,返回null。
System.out.println("llist.pollLast():" + list.pollLast());
System.out.println("llist:" + list);
// (03) 获取最后一个元素。          失败的话,返回null。
System.out.println("llist.peekLast():" + list.peekLast());

//不建议在LinkedList中使用下面俩个操作,因为效率低,需要进行检索
//替换元素
list.set(1, "10");
System.out.println(list.get(1));

//将LinkedList转换成数组
String[] arr = (String[]) list.toArray();
for (String s : arr)
System.out.println(s);
// 输出大小
System.out.println("size:" + list.size());
// 清空LinkedList
list.clear();
// 判断LinkedList是否为空
System.out.println("isEmpty():" + list.isEmpty() + "\n");
}

/**
* 将LinkedList当做LIFO(后进先出)的堆栈
*/
private static void useLinkedFIFO() {
LinkedList<Integer> stack = new LinkedList<>();

//进栈
stack.push(1);
stack.push(2);

//打印栈
System.out.println(stack);

//删除栈顶元素
System.out.println("stack.pop:" + stack.pop());
// 取出“栈顶元素”
System.out.println("stack.peek():" + stack.peek());

// 打印“栈”
System.out.println("stack:" + stack);
}

/**
* 将LinkedList当作 FIFO(先进先出)的队列
*/
private static void useLinkedListAsFIFO() {
System.out.println("\nuseLinkedListAsFIFO");
// 新建一个LinkedList
LinkedList queue = new LinkedList();

// 将10,20,30,40添加到队列。每次都是插入到末尾
queue.add("10");
queue.add("20");
queue.add("30");
queue.add("40");
// 打印“队列”
System.out.println("queue:" + queue);

// 删除(队列的第一个元素)
System.out.println("queue.remove():" + queue.remove());

// 读取(队列的第一个元素)
System.out.println("queue.element():" + queue.element());

// 打印“队列”
System.out.println("queue:" + queue);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: