1. 什么是链表
链表是一种物理存储结构上非连续的存储结构,是线性表的一种。
使用链表的原因:链表和顺序表同属于一种线性表但是顺序表有扩容浪费空间,以及中间位置插入元素和删除元素需要移动大量的数据效率低的缺点,使用链表则可以解决这些问题。
2. 链表的种类
- 单向,双向
- 带头,不带头
- 循环,非循环
重点掌握:无头单向非循环链表,一般是配合其他数据结构使用,如哈希桶,图等等;另一个就是无头双向链表。
3. 创建单链表
单链表由两个类组成,一个类用来存储单链表中节点的元素以及指向下一个节点的地址,相当于现实社会中的火车车厢,每节车厢通过铁链相连,铁链相当于指向下一个节点的地址,只有知道地址才能使两个节点相连。每节车厢存放不同的物品就是节点中的元素。有了车厢才能组成一辆火车,所以另一个类就是火车类,存储的是单链表中实际存储的元素和单链表的头节点。
3.1 创建 Node 类(车厢类)
/**
* 车厢类
*/
public class Node {
// 存储具体元素
int data;
// 存储下一个节点的地址
Node next;
public Node(int data) {
this.data = data;
}
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
}
3.2 创建 MySingleList (火车类)
public class MySingleList {
// 链表中的实际存储元素
private int size;
// 链表中的头节点
private Node head;
}
4. 单链表的基本操作
4.1 增加链表元素
4.1.1 在链表头部添加元素
public void firstAdd(int data) {
// 关注临界条件
// 1.链表中有没有节点,判空
// 2.链表中已经有节点了
if (size == 0) {
// 1. 先创建一个新节点存放 data 值
Node node = new Node(data);
// 2. 头节点变为新加入的节点
head = node;
size++;
} else {
// 1. 先创建一个新节点存放 data 值
Node node = new Node(data);
// 2. 将新节点与原来的第一个节点连接
node.next = head;
// 3. 将头节点变为新的节点
head = node;
size++;
}
}
图解:
4.1.2 在链表任意位置添加元素
在 index 位置插入新节点要先找到前驱节点,为什么找前驱节点,因为单链表特点是只能从前往后遍历,所以要在任意位置添加节点要先知道它的前驱节点。添加步骤:先要使新节点与原来该位置的节点相连,并且将原来的前驱节点与新节点相连,这样就添加成功了。
public void indexAdd(int index, int data) {
// 边界条件:1. 链表是否为空 2. 索引是否合法 3. index 是否是第一个节点
// 1. 链表是否为空
if (size == 0) {
System.err.println("链表为空!");
} else if (index < 0 || index > size) {
//2. 索引是否合法
System.err.println("索引非法!");
} else if (index == 0) {
// 3. index 是否是第一个节点
firstAdd(data);
} else {
Node node = new Node