链表(LinkedList)具有的特性
- 顺序访问会非常高效,而随机访问效率比较低
- 插入、删除操作效率比较高
链表实现的关键
linkedList为双链表,里面维护了一个first和last指针,而每个节点有item自身、prev和next两个节点来维护双链表的关系,所以顺序访问,插入,删除相比ArrayList 要高效,但是随机读取却没有ArrayList高效,所以需要按实际场景来选择使用那种数据类型。
以下是LinkedList 实现的关键代码实现,
package com.yenroc.linkedlist;
import java.util.NoSuchElementException;
public class LinkedList<E> {
class Node<E>{
// 元素
E e;
// 前一个元素
Node<E> prev;
// 下一个元素
Node<E> next;
public Node(Node<E> prev, E e, Node<E> next) {
this.e = e;
this.next = next;
this.prev = prev;
}
}
private int size;// 链表长度
private Node<E> first;// 头链表
private Node<E> last;// 尾链表
public LinkedList() {}
// 往头部添加元素
public void addFirst(E e){
final Node<E> oldFirst = first;
// 创建新的头节点,把原来的头节点当做新的头节点的下一个
final Node<E> newFirst = new Node<>(null, e, oldFirst);
first = newFirst;
if (oldFirst == null){// 第一次添加元素
System.out.println("链表第一次添加元素");
last = newFirst;// 首为空,则 为肯定为空,则尾和首一样
} else {
oldFirst.prev = newFirst;// 把原本的头节点的上一个元素指向新的头节点
}
size++;
}
// 往尾部添加元素
public void addLast(E e){
final Node<E> oldLast = last;
final Node<E> newLast = new Node<>(oldLast, e, null);
last = newLast;
if (oldLast == null) {// 第一次添加元素
System.out.println("链表第一次添加元素");
first = newLast;
} else {
oldLast.next = newLast; // 原本的尾节点的下一个元素指向新的尾节点
}
size++;
}
// 往链表添加元素,添加到尾部
public boolean add(E e) {
addLast(e);
return true;
}
public E getFirst() {
if (first == null) {
throw new NoSuchElementException("链表元素为空");
}
return first.e;
}
public E getLast() {
if (last == null) {
throw new NoSuchElementException("链表元素为空");
}
return last.e;
}
// 删除头元素,头元素的next 元素给first,并清空prev,代码同removeLast
public void removeFirst(){
}
// 删除尾元素,并返回尾元素
public E removeLast(){
if (last == null) {
throw new NoSuchElementException("链表元素为空");
}
final E element = last.e;
final Node<E> newLast = last.prev;// 原来的最后元素的上一个元素作为最后一个元素
last = newLast;
if (newLast == null){// 原本就一个元素,还把最后一个给remove,则把头直控
newLast.prev = null;
} else {
newLast.next = null;// 最后一个元素不需要next有元素
}
size--;
return element;
}
public void add(int index, E e) {
if (index == size) {
addLast(e);
}
Node node = node(index);
final Node<E> pred = node.prev;
final Node newCur = new Node(pred, e, node);// 原本的上一个 当作新的上一个,原本的元素作为新的next
node.prev = newCur;
if (pred == null) {// 说明原本的数据就是first;
first = newCur;
} else {
pred.next = newCur;// 让原本的上一个的元素next 指向当前插入的元素
}
size++;
}
Node<E> node(int index) {
// 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 void printLinkedList(){
Node temp = first;
while (true){
if (temp == null) {
return;
}
System.out.print(temp.e+"\t");
temp = temp.next;
}
}
}
至此简单的链表功能就已经实现了,下面测试下效果