链表 (Linked List)
链表 (Linked List)
链表是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
基础概念
链表类型
- 单链表
1 -> 2 -> 3 -> 4 -> NULL
- 双链表
NULL <- 1 <-> 2 <-> 3 <-> 4 -> NULL
- 环形链表
1 -> 2 -> 3 -> 4
^ |
| v
7 <- 6 <- 5 <- 4
基本操作
- 插入:在指定位置添加新节点
- 删除:移除指定节点
- 查找:遍历查找特定值
- 反转:改变链表方向
- 合并:将多个链表合并
- 检测环:判断是否存在循环
应用场景
- 动态内存分配
- 实现队列/栈
- LRU缓存系统
- 多项式计算
- 图的邻接表表示
经典问题
1. 反转链表
LeetCode 206 - Reverse Linked List
将链表反向的过程:
原始链表:
1 -> 2 -> 3 -> 4 -> NULL
反转过程:
1 -> 2 -> 3 -> 4 -> NULL
^
NULL <- 1 2 -> 3 -> 4
^
NULL <- 1 <- 2 3 -> 4
^
NULL <- 1 <- 2 <- 3 4
^
NULL <- 1 <- 2 <- 3 <- 4
def reverseList(head):
prev = None
curr = head
while curr:
next_node = curr.next
curr.next = prev
prev = curr
curr = next_node
return prev
2. 合并有序链表
LeetCode 21 - Merge Two Sorted Lists
合并过程示意:
输入:
l1: 1 -> 3 -> 5 -> NULL
l2: 2 -> 4 -> 6 -> NULL
步骤:
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> NULL
def mergeTwoLists(l1, l2):
dummy = ListNode(0)
curr = dummy
while l1 and l2:
if l1.val < l2.val:
curr.next = l1
l1 = l1.next
else:
curr.next = l2
l2 = l2.next
curr = curr.next
curr.next = l1 or l2
return dummy.next
3. 检测环
LeetCode 141 - Linked List Cycle
使用快慢指针检测环:
环形链表示例:
1 -> 2 -> 3 -> 4
^ |
| v
7 <- 6 <- 5
检测过程:
第1步: 1 -> 2 -> 3 -> 4 -> 5
s f
第2步: 1 -> 2 -> 3 -> 4 -> 5
s f
第3步: 1 -> 2 -> 3 -> 4 -> 5
s f
def hasCycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
4. LRU缓存
使用双向链表和哈希表实现LRU缓存:
双向链表示例:
head <-> key1 <-> key2 <-> key3 <-> tail
访问key2后:
head <-> key1 <-> key3 <-> key2 <-> tail
插入key4,缓存满:
head <-> key3 <-> key2 <-> key4 <-> tail
class Node:
def __init__(self, key=0, value=0):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
self.cache = {}
self.head = Node()
self.tail = Node()
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key):
if key in self.cache:
node = self.cache[key]
self._remove(node)
self._add(node)
return node.value
return -1
def put(self, key, value):
if key in self.cache:
self._remove(self.cache[key])
node = Node(key, value)
self._add(node)
self.cache[key] = node
if len(self.cache) > self.capacity:
node = self.head.next
self._remove(node)
del self.cache[node.key]
def _remove(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def _add(self, node):
node.prev = self.tail.prev
node.next = self.tail
self.tail.prev.next = node
self.tail.prev = node
常见技巧
- 使用哨兵节点(dummy node)简化头节点的处理
- 快慢指针解决环检测、中点查找等问题
- 多指针技术处理复杂的链表操作
- 递归和迭代两种方式实现链表操作
- 画图帮助理解复杂的链表操作
相关题目
- LeetCode 19 - Remove Nth Node From End of List
- LeetCode 23 - Merge k Sorted Lists
- LeetCode 142 - Linked List Cycle II
- LeetCode 160 - Intersection of Two Linked Lists
- LeetCode 234 - Palindrome Linked List