首先看下官网的一张图继承关系:

LinkedList 和 ArrayList 的区别:
- 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
- 2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
- 3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
LinkedList 的简单使用
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
for (int i = 0; i < 5; i++) {
list.add("这是第 " + i + " 个");
}
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
}
LinkedList 是通过双链表实现的,数据结构
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;
}
}
修改指定位置数据「set 」
public E set(int index, E element) {
checkElementIndex(index); // 检查角标是否越界 (index >= 0 && index < size;)
Node<E> x = node(index); // 取出 index 位置的数据
E oldVal = x.item; // 取出原有的值用于返回
x.item = element; // 修改其值
return oldVal; // 返回原有的值
}
取出指定位置的元素「node」
/**
* 取出指定位置的元素
* 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;
}
}
获取元素「get」
/**
* 返回指定位置元素
*/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
先看下添加方法「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;
else
l.next = newNode; // 将之前尾部元素后驱指针指向新元素
size++;
modCount++;
}
移除操作「remove」
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
/**
* Unlinks non-null node x.
*/
E unlink(Node<E> x) {
// assert x != null;
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; // 置空方便gc
}
if (next == null) { // 说明是在链表尾
last = prev; // 后指针直接是该元素的前驱
} else {
next.prev = prev; // 后面元素的前驱是该元素的前驱
x.next = null; // 置空
}
x.item = null;
size--;
modCount++;
return element;
}
插入多个元素「addAll」
public boolean addAll(Collection<? extends E> c) {
return addAll(size, 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;
}
// 构建由该数组组成的链表 (之后在将这段链表插入到原来链表中,整段插入)
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;
}
再回头看下开始说的区别
-
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
-
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
LinkedList 的 get 和 set 都要执行 node(int index) 方法获取指定位置元素,在 node 方法中判断该 index 是靠前还是靠后,分别从不同方向进行遍历
-
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
LinedList 的 add 是直接添加到尾部,只需要修改下指针.同理 remove 的操作也是修改指针即可.
网友评论