链表的基本原理
一 单链表
- 链表的基本操作
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
// 输入一个数组,转换为一条单链表
ListNode createLinkedList(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
ListNode head = new ListNode(arr[0]);
ListNode cur = head;
for (int i = 1; i < arr.length; i++) {
cur.next = new ListNode(arr[i]);
cur = cur.next;
}
return head;
}
- 查/改
2.1. 单链表的遍历/查找/修改
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 遍历单链表
for (ListNode p = head; p != null; p = p.next) {
System.out.println(p.val);
}
- 增
3.1. 在单链表头部插入新元素
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 在单链表头部插入一个新节点 0
ListNode newHead = new ListNode(0);
newHead.next = head;
head = newHead;
// 现在链表变成了 0 -> 1 -> 2 -> 3 -> 4 -> 5
3.2. 在单链表尾部插入新元素
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 在单链表尾部插入一个新节点 6
ListNode p = head;
// 先走到链表的最后一个节点
while (p.next != null) {
p = p.next;
}
// 现在 p 就是链表的最后一个节点
// 在 p 后面插入新节点
p.next = new ListNode(6);
// 现在链表变成了 1 -> 2 -> 3 -> 4 -> 5 -> 6
3.3. 在单链表中间插入新元素
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 在第 3 个节点后面插入一个新节点 66
// 先要找到前驱节点,即第 3 个节点
ListNode p = head;
for (int i = 0; i < 2; i++) {
p = p.next;
}
// 此时 p 指向第 3 个节点
// 组装新节点的后驱指针
ListNode newNode = new ListNode(66);
newNode.next = p.next;
// 插入新节点
p.next = newNode;
// 现在链表变成了 1 -> 2 -> 3 -> 66 -> 4 -> 5
3.4. 在单链表中删除一个节点
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除第 4 个节点,要操作前驱节点
ListNode p = head;
for (int i = 0; i < 2; i++) {
p = p.next;
}
// 此时 p 指向第 3 个节点,即要删除节点的前驱节点
// 把第 4 个节点从链表中摘除
p.next = p.next.next;
// 现在链表变成了 1 -> 2 -> 3 -> 5
3.5. 在单链表尾部删除元素
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除尾节点
ListNode p = head;
// 找到倒数第二个节点
while (p.next.next != null) {
p = p.next;
}
// 此时 p 指向倒数第二个节点
// 把尾节点从链表中摘除
p.next = null;
// 现在链表变成了 1 -> 2 -> 3 -> 4
3.6. 在单链表头部删除元素
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除头结点
head = head.next;
// 现在链表变成了 2 -> 3 -> 4 -> 5
二 双链表
- 创建双链表
class DoublyListNode {
int val;
DoublyListNode next, prev;
DoublyListNode(int x) { val = x; }
}
DoublyListNode createDoublyLinkedList(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
DoublyListNode head = new DoublyListNode(arr[0]);
DoublyListNode cur = head;
// for 循环迭代创建双链表
for (int i = 1; i < arr.length; i++) {
DoublyListNode newNode = new DoublyListNode(arr[i]);
cur.next = newNode;
newNode.prev = cur;
cur = cur.next;
}
return head;
}
- 查改
2.1 双链表的遍历/查找/修改
// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
DoublyListNode tail = null;
// 从头节点向后遍历双链表
for (DoublyListNode p = head; p != null; p = p.next) {
System.out.println(p.val);
tail = p;
}
// 从尾节点向前遍历双链表
for (DoublyListNode p = tail; p != null; p = p.prev) {
System.out.println(p.val);
}
- 增
3.1 在双链表头部插入新元素
// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
// 在双链表头部插入新节点 0
DoublyListNode newHead = new DoublyListNode(0);
newHead.next = head;
head.prev = newHead;
head = newHead;
// 现在链表变成了 0 -> 1 -> 2 -> 3 -> 4 -> 5
3.2 在双链表尾部插入新元素
// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
DoublyListNode tail = head;
// 先走到链表的最后一个节点
while (tail.next != null) {
tail = tail.next;
}
// 在双链表尾部插入新节点 6
DoublyListNode newNode = new DoublyListNode(6);
tail.next = newNode;
newNode.prev = tail;
// 更新尾节点引用
tail = newNode;
// 现在链表变成了 1 -> 2 -> 3 -> 4 -> 5 -> 6
3.3 在双链表中间插入新元素
// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
// 在第 3 个节点后面插入新节点 66
// 找到第 3 个节点
DoublyListNode p = head;
for (int i = 0; i < 2; i++) {
p = p.next;
}
// 组装新节点
DoublyListNode newNode = new DoublyListNode(66);
newNode.next = p.next;
newNode.prev = p;
// 插入新节点
p.next.prev = newNode;
p.next = newNode;
// 现在链表变成了 1 -> 2 -> 3 -> 66 -> 4 -> 5
- 删
4.1 在双链表中删除一个节点
// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除第 4 个节点
// 先找到第 3 个节点
DoublyListNode p = head;
for (int i = 0; i < 2; i++) {
p = p.next;
}
// 现在 p 指向第 3 个节点,我们它后面那个节点摘除出去
DoublyListNode toDelete = p.next;
// 把 toDelete 从链表中摘除
p.next = toDelete.next;
toDelete.next.prev = p;
// 把 toDelete 的前后指针都置为 null 是个好习惯(可选)
toDelete.next = null;
toDelete.prev = null;
// 现在链表变成了 1 -> 2 -> 3 -> 5
4.2 在双链表头部删除元素
// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除头结点
DoublyListNode toDelete = head;
head = head.next;
head.prev = null;
// 清理已删除节点的指针
toDelete.next = null;
// 现在链表变成了 2 -> 3 -> 4 -> 5
4.3 在双链表尾部删除元素
// 创建一条双链表
DoublyListNode head = createDoublyLinkedList(new int[]{1, 2, 3, 4, 5});
// 删除尾节点
DoublyListNode p = head;
// 找到尾结点
while (p.next != null) {
p = p.next;
}
// 现在 p 指向尾节点
// 把尾节点从链表中摘除
p.prev.next = null;
// 把被删结点的指针都断开是个好习惯(可选)
p.prev = null;
// 现在链表变成了 1 -> 2 -> 3 -> 4

浙公网安备 33010602011771号