LinkedList是一个基于双向链表的数据结构,在多线程的环境下是不安全的。
因为它是基于链表实现的,所以对它的一切访问操作都会很慢,比如:
增:
若是在链表头部或尾部进行添加元素操作,只需要在每次添加元素时用head和tail来标记链表的头和尾,这样的话增加操作就会很快了;若是在链表中间插入一个元素,最好的方法也只有二分法,本质也就是for循环来进行查找和定位,链表越长,效率越低
删除:
流程和增加操作一样
改和查:
每次进行这两个操作都需要定位到相应的位置,本质也是for循环,效率低下
因为是双向链表,它的基本操作都比较简单,所以就不在这里贴代码了,相应的
我们来看看重点:
LinkedList里既为我们提供了普通的增删改查操作方法(传参时只需传递一个参数),又给我们提供了根据索引来增删改查操作它的方法。我们来看看根据索引的增删改查操作
增:
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));
}
查:
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;
}
每个方法里都调用了一个构造方法node(int 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;
}
}
可以看出,这个构造方法首先需要我们给出一个索引index,通过这个索引来进行判断:首先获取链表中点索引i,若此索引index处于链表的左侧index<i/2则从链表的头部开始进行for循环,直到找到这个元素;若此索引index处于链表的右侧index>i/2则从链表的尾部开始进行for循环,直到找到这个元素
即上述增删改方法都需要首先定位到指定元素,然后才能再进行相应的操作。
虽然此方法使用二分法来降低查找的复杂度,但是在链表很长的情况下查找效率还是非常低下的,最好的办法应该是对链表的头尾来操作,但是这种情况实在是太少了。
来做个测试:
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
public class speed {
int j = 100;
@Test
public void tt() {
long time = System.currentTimeMillis();
List linkedList = new LinkedList();
for (int i = 0; i < j; i++)
linkedList.add(i);
for (int i = 0; i < linkedList.size(); i++) {
linkedList.get(i);
System.out.println("LinkedList遍历速度:" + (System.currentTimeMillis() - time) + "ms");
}
}
}
循环向LinkedList中插入100个元素,然后取出并计时
结果:
...
LinkedList遍历速度:0ms
LinkedList遍历速度:1ms
LinkedList遍历速度:2ms
LinkedList遍历速度:3ms
接下来1000个,试一下,结果:
...
LinkedList遍历速度:59ms
LinkedList遍历速度:60ms
可以发现,插入的元素越多,取出时所耗时越久。所以,遍历它最好不要使用for循环去做。
遍历方法:
1、for循环
LinkedList list =new LinkedList();
l.add(1);
l.add(2);
l.add(3);
l.add(4);
for(int i=0;i<l.size();i++)
System.out.print(l.get(i) + " ");
这种方法并不推荐,因为每次调用get方法去取值都要遍历LinkedList的前半部分或后半部分,效率低
2、使用Iterator
for(Iterator it2 = list.iterator();it2.hasNext();){
System.out.println(it2.next());
}
或者
Iterator it1 = list.iterator();
while(it1.hasNext()){
System.out.println(it1.next());
}
推荐使用此方法,耗时较低
3、增强for循环
for(String tmp:list){
System.out.println(tmp);
}
推荐使用此方法,耗时较低