数据结构之链表
链表
特点:
节点内部包含指向下一个节点的指针,这种称为单链表
既有下个节点也有上个节点的指针,这种称为双向链表
链表又分为带头结点和不带头结点的
链表的一些基本套路
假设链表为如下数据结构:
class ListNode {
int val;
ListNode next;
public ListNode() {}
public ListNode(int val) {this.val = val;}
}
快慢指针
所谓快慢指针,就是快指针每次移动两个节点,慢指针每次移动一个节点。
经常用于寻找一个链表的中间节点。
或者判断链表是否有环
public ListNode getMid(ListNode head) {
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
反转链表
反转链表,链表操作的入门级题目了。
主要是理解指向操作。
比如下面代码中的pre = cur;
不是单纯地赋值操作。可以理解成pre指向cur节点。
动图表示就是pre指针往后移动了一位,指向了cur。我不会画动图,网上有可以看看。
指向操作可以说是理解链表的基础。这一题也要好好理解。
public ListNode reverse(ListNode node) {
ListNode cur = head, pre = null;
while (cur != null) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
合并有序链表
也是入门级别的操作了。其中引入了dummyHead是解决很多链表问题的常用套路。
合并有序链表也是解决很多链表问题的步骤之一。比如链表排序。
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummyHead = new ListNode(1);
ListNode cur = dummyHead;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
cur.next = l1;
l1 = l1.next;
} else {
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1 == null ? l2 : l1;
return dummyHead.next;
}