一、单链表介绍
链表是一种不需要连续内存空间的线性表。
而单链表是最简单的链表。可以将单链表想象成如下图所示:

每个内存块被称为结点。
每个结点有一个 数据域和指针域,数据域用来存储数据,而指针 域用来保存下一个结点的地址。
单链表的尾结点指向 NULL。
二、插入
只需要改变相邻结点的指针的指向,就可以实现单链表的插入,时间复杂度为 O(1)。
如图所示:

翻译成代码:
/**
* 将新的节点插入到指定节点后
*
* @param preNode 指定节点
* @param newNode 新的节点
*/
public void insert(Node<T> preNode, Node<T> newNode) {
newNode.next = preNode.next;
preNode.next = newNode;
length++;
}
三、删除
和插入类似,只需要相邻结点的指针指向,就可以完成单链表的删除操作。时间复杂度为 O(1)。
如图所示:

翻译成代码就是:
/**
* 给定被删除元素的前一个结点,删除下一个结点
*
* @param preNode
*/
public void del(Node preNode) {
preNode.next = preNode.next.next;
length--;
}
四、查找
由于单链表不需要连续的内存空间,所以不需要搬运数据,插入和删除的时间复杂度很低,为 O(1)。
但是有利就有弊,由于内存空间不连续,所以想要找到第 k 个结点,就只能通过遍历的方式。时间复杂度为 O(n)。
/**
* 访问第 k 个结点, k 从 0 开始
*
* @param k
* @return
*/
public Node find(int k) {
int cnt = 0;
Node temp = head;
// 找到第 k 个元素
while (cnt != k) {
temp = temp.next;
cnt++;
}
return temp;
}
五、总结
单链表是链表最简单的一种,和数组一样,链表属于线性表。
单链表的插入和删除操作非常方便,时间复杂度为 O(1)。
单链表随机访问第 k 个结点的时间复杂度为 O(n)。
六、完整代码
/**
* 单链表的实现
*
* @author liyanan
* @date 2020/1/2 13:16
*/
public class SingleLinkedList<T> {
public static class Node<T> {
/**
* 存储数据
*/
public T data;
/**
* 指向下一个节点
*/
public Node next;
public Node(T data) {
this.data = data;
}
}
/**
* 单链表的头结点,该节点不存储有效数据,只是为了方便
*/
private Node<T> head;
/**
* 单链表的长度
*/
private int length;
public SingleLinkedList() {
head = null;
length = 0;
}
/**
* 插入节点到单链表尾部
*
* @param newNode
*/
public void insertLast(Node<T> newNode) {
if (length == 0) {
head = newNode;
length++;
} else {
Node<T> temp = head;
// 找到链表尾结点
while (temp.next != null) {
temp = temp.next;
}
insert(temp, newNode);
}
}
/**
* 将新的节点插入到指定节点后
*
* @param preNode 指定节点
* @param newNode 新的节点
*/
public void insert(Node<T> preNode, Node<T> newNode) {
newNode.next = preNode.next;
preNode.next = newNode;
length++;
}
public void insertFirst(Node<T> newNode) {
if (length == 0) {
head = newNode;
} else {
newNode.next = head;
head = newNode;
}
length++;
}
/**
* 删除数据域为指定值的元素
*
* @param e
*/
public void del(T e) {
Node temp = head;
while (temp != null) {
if (temp.next.data.equals(e)) {
del(temp);
return;
}
temp = temp.next;
}
}
/**
* 给定被删除元素的前一个结点,删除下一个结点
*
* @param preNode
*/
public void del(Node preNode) {
preNode.next = preNode.next.next;
length--;
}
/**
* 访问第 k 个结点, k 从 0 开始
*
* @param k
* @return
*/
public Node find(int k) {
int cnt = 0;
Node temp = head;
// 找到第 k 个元素
while (cnt != k) {
temp = temp.next;
cnt++;
}
return temp;
}
/**
* 打印单链表所有有效结点
*
* @return
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Node temp = head;
while (temp != null) {
sb.append(temp.data);
sb.append(" -> ");
temp = temp.next;
}
sb.append("null, length = ");
sb.append(length);
return sb.toString();
}
public static void main(String[] args) {
SingleLinkedList<Integer> single = new SingleLinkedList<>();
Node<Integer> node1 = new Node<>(1);
Node<Integer> node2 = new Node<>(2);
Node<Integer> node3 = new Node<>(3);
Node<Integer> node4 = new Node<>(4);
Node<Integer> node5 = new Node<>(5);
single.insertLast(node1);
single.insertLast(node2);
single.insertLast(node3);
single.insertLast(node4);
single.insertLast(node5);
System.out.println(single);
single.insert(node1, new Node<>(10));
System.out.println(single);
single.del(node3);
System.out.println(single);
single.del(5);
System.out.println(single);
Node node = single.find(0);
System.out.println(node.data);
}
}