Java中LinkedList原理代码解析
介绍
Java中的LinkedList是一种双向链表数据结构,在实际开发中经常被使用。LinkedList实现了List和Deque接口,可以被用作列表或队列。本文将深入探究LinkedList的实现原理和相应的代码解析。
LinkedList实现原理
LinkedList的实现原理主要包括以下几点:
- 内部节点类
LinkedList实现了一个节点类Node用来存储元素以及前后指针信息,如下所示:
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;
}
}
- 头节点和尾节点
LinkedList内部通过head存储头节点,通过tail存储尾节点。头节点和尾节点都是特殊的空节点,不存储元素。通过头节点和尾节点可以快速访问元素,如下所示:
transient Node<E> first;
transient Node<E> last;
- 元素数量
LinkedList内部通过一个整型变量size记录元素的数量,如下所示:
transient int size = 0;
- 双向链表实现
LinkedList实现了List和Deque接口,因此是一种双向链表。双向链表的特点是节点除了存储后继节点的指针外,还存储前驱节点的指针,因此可以双向遍历链表。
LinkedList的主要方法
LinkedList内部实现了很多方法,其中最常用的几个方法包括:add、remove、get、set等。以下是这些方法的详细说明。
add方法
add方法有两个重载方法,可以添加元素到列表中的指定位置或列表尾部。默认添加到列表尾部。add方法的实现主要分为两种情况:
- 添加到列表末尾
添加到列表末尾时,会先新建一个节点类,并将新节点的prev指向尾节点last,将尾节点last的next指向新节点,将尾节点指向新节点,最后将元素数量size加1,如下所示:
public boolean add(E e) {
linkLast(e);
return true;
}
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++;
}
- 添加到指定位置
添加到指定位置时,会先判断插入的索引位置是否在列表头或者列表尾,若是,则直接调用linkFirst或linkLast方法,否则获取插入位置对应的节点,将新节点的prev指向插入位置节点的prev,插入位置节点的prev的next指向新节点,新节点的next指向插入位置节点,插入位置节点的prev指向新节点,最后将元素数量size加1,如下所示:
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
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++;
}
remove方法
remove方法有两个重载方法,可以删除列表中指定索引位置或指定元素。默认删除列表第一个匹配的元素。remove方法的实现主要分为两种情况:
- 删除指定索引位置的元素
删除指定索引位置的元素时,先获取要删除的节点,将要删除节点的前一个节点的next指向要删除的节点的next,将要删除节点的下一个节点的prev指向要删除的节点的prev,最后将要删除节点的prev和next置为null,元素数量size减1,如下所示:
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
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--;
return element;
}
- 删除指定元素
删除指定元素时,先遍历列表找到第一个匹配的元素,然后将第一个匹配元素节点的prev的next指向第一个匹配元素节点的next,第一个匹配元素节点的next的prev指向第一个匹配元素节点的prev,最后将第一个匹配元素节点的prev和next置为null,元素数量size减1,如下所示:
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;
}
get方法
get方法有一个重载方法,用于获取列表中指定索引位置的元素。实现逻辑较为简单,先获取指定索引位置的节点信息,然后返回节点中存储的元素,如下所示:
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
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;
}
}
set方法
set方法有一个重载方法,用于将列表中指定索引位置的元素替换为指定元素。先获取指定索引位置的节点信息,然后将节点中存储的元素替换为指定元素并返回原来存储的元素,如下所示:
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
示例说明
以下示例演示了如何使用LinkedList实现队列和栈两种数据结构。
1. 队列
队列是一种先进先出的数据结构,LinkedList可以被用作队列的实现。以下是一个自定义的Queue类的示例代码:
public class Queue<E> {
private LinkedList<E> list = new LinkedList<>();
public void enqueue(E e) {
list.addLast(e);
}
public E dequeue() {
return list.removeFirst();
}
public boolean isEmpty() {
return list.isEmpty();
}
public int size() {
return list.size();
}
}
2. 栈
栈是一种先进后出的数据结构,LinkedList可以被用作栈的实现。以下是一个自定义的Stack类的示例代码:
public class Stack<E> {
private LinkedList<E> list = new LinkedList<>();
public void push(E e) {
list.addFirst(e);
}
public E pop() {
return list.removeFirst();
}
public boolean isEmpty() {
return list.isEmpty();
}
public int size() {
return list.size();
}
}
总结
本文介绍了Java中LinkedList的实现原理和相应的代码解析。LinkedList是一种双向链表数据结构,通过head存储头节点和tail存储尾节点,以及记录元素数量size来实现列表和队列。LinkedList内部实现了很多常用的方法,如add、remove、get、set等,可以方便地实现自定义的数据结构,如队列和栈等。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中LinkedList原理代码解析 - Python技术站