《漫画算法--小灰的算法之旅》
今日主要学习链表的插入操作和删除操作
package com.java.array;
public class LinkedList {
private Node head; // 头节点指针
private Node last; // 尾节点指针
private int size; // 链表的实际长度
/**
* 链表插入元素
*
* @param data 插入元素
* @param index 插入位置
*/
public void insert(int data, int index) throws Exception {
if (index < 0 || index > size) { // index > size 说的是当前链表的长度是size,不可能在大于size的索引处插入元素,可以在等于size的位置插入元素
throw new IndexOutOfBoundsException("index is illegal");
}
Node<Integer> insertedNode = new Node<>(data); // 将插入的字段,封装成Node类
if (size == 0) { // (1) 链表为空
head = insertedNode;
last = insertedNode;
} else if (index == 0) { // (2) 插入头部
insertedNode.next = head; // 把新节点的next指针,指向原先的头节点
head = insertedNode; // 新节点变为链表的头节点
} else if (index == size) { // (3) 插入尾部
last.next = insertedNode; // 把最后一个节点的next指针,指向新插入的节点
last = insertedNode; // 把新插入节点指向尾节点指针
} else { // 插入中间
Node prevNode = get(index - 1);// 查找指定位置元素
insertedNode.next = prevNode.next;
prevNode.next = insertedNode; // 此处需要自己画图进行理解,单向链表
}
size++;
}
/**
* 链表删除元素
*
* @param index 删除的位置
* @return 返回删除的节点 Node
*/
public Node remove(int index) {
reviewIndex(index);
Node removeNode = null;
if (index == 0) { // (1) 删除头节点
removeNode = head;
head = head.next;
} else if (index == size - 1) { // (2) 删除尾部节点
Node prevNode = get(index - 1);
removeNode = prevNode.next;
prevNode.next = null;
last = prevNode;
} else { // 删除中间元素
Node prevNode = get(index - 1);
removeNode = prevNode.next;
prevNode.next = prevNode.next.next;
}
size--;
return removeNode;
}
/**
* @param index 指定位置索引
*/
public Node get(int index) {
reviewIndex(index);
Node tmp = head;
for (int i = 0; i < index; i++) {
tmp = tmp.next;
}
return tmp;
}
// 输入下标的异常检测
private void reviewIndex(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("index is illegal");
}
}
// 输出链表
public void output() {
Node tmp = head;
while (tmp != null) {
System.out.println(tmp.data);
tmp = tmp.next;
}
}
// 链表节点
private static class Node<E> {
E data;
Node<E> next;
Node<E> prev;
public Node(E data) {
this.data = data;
}
public Node(E data, Node<E> next, Node<E> prev) {
this.data = data;
this.next = next;
this.prev = prev;
}
}
}
注意:
(1)尾节点指针只在插入空链表、插入尾节点、删除尾节点才需要进行考虑
数据和链表的对比:
查找 | 更新 | 插入 | 删除 | |
数组 | O(1) | O(1) | O(n) | O(n) |
链表 | O(n) | O(n) | O(1) | O(1) |
数组适合读操作多,写操作少的场景,链表适合插入和删除,读操作少的场景
附件 JDK源码中的LinkedList继承关系。