单链表反转是数据结构与算法中的经典问题,它不仅考察对链表结构的理解,也考验编程思维和技巧。本文将带你从基础实现到高级应用,全面掌握单链表反转。
1. 理解单链表
在深入反转算法之前,我们先回顾单链表的基本结构:
python
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
单链表的特点是每个节点包含数据和指向下一个节点的指针,只能单向遍历。
2. 基础反转方法
2.1 迭代法(最常用)
核心思想:逐个改变节点指向,从前往后反转。
python
def reverse_list_iterative(head):
prev = None
current = head
while current:
# 保存下一个节点
next_temp = current.next
# 反转指针
current.next = prev
# 移动指针
prev = current
current = next_temp
return prev # 新的头节点
执行过程可视化:
python
原链表: 1 → 2 → 3 → 4 → 5 → None
步骤1: None ← 1 2 → 3 → 4 → 5 → None
步骤2: None ← 1 ← 2 3 → 4 → 5 → None
步骤3: None ← 1 ← 2 ← 3 4 → 5 → None
...
结果: None ← 1 ← 2 ← 3 ← 4 ← 5
2.2 递归法
核心思想:通过递归到达链表末端,然后从后往前反转。
python
def reverse_list_recursive(head):
# 递归终止条件
if not head or not head.next:
return head
# 递归到最后一个节点
new_head = reverse_list_recursive(head.next)
# 反转指针
head.next.next = head
head.next = None
return new_head
递归过程分析:
scss
reverse(1)
reverse(2)
reverse(3)
reverse(4)
reverse(5) → 返回5
5.next = 4, 4.next = None
5.next = 3, 3.next = None
5.next = 2, 2.next = None
5.next = 1, 1.next = None
3. 进阶反转技巧
3.1 反转部分链表
反转链表中从位置 m 到 n 的部分:
python
def reverse_between(head, m, n):
if not head or m == n:
return head
dummy = ListNode(0)
dummy.next = head
prev = dummy
# 移动到第m-1个节点
for _ in range(m - 1):
prev = prev.next
# 开始反转
current = prev.next
for _ in range(n - m):
temp = current.next
current.next = temp.next
temp.next = prev.next
prev.next = temp
return dummy.next
3.2 K个一组反转链表
每 k 个节点一组进行反转,不足 k 的保持原样:
python
def reverse_k_group(head, k):
def reverse_sublist(start, end):
prev, curr = None, start
while curr != end:
next_temp = curr.next
curr.next = prev
prev = curr
curr = next_temp
return prev
# 检查是否有k个节点
node = head
for _ in range(k):
if not node:
return head
node = node.next
# 反转前k个节点
new_head = reverse_sublist(head, node)
# 递归处理剩余部分
head.next = reverse_k_group(node, k)
return new_head
3.3 交替反转
第一个k个节点反转,下一个k个节点保持,如此交替:
python
def reverse_alternate_k_nodes(head, k):
if not head or k <= 1:
return head
current = head
prev = None
reverse = True
while current:
if reverse:
# 反转k个节点
section_start = current
section_prev = None
count = 0
# 检查是否有足够的节点
temp = current
for _ in range(k):
if not temp:
break
temp = temp.next
# 反转当前段
while current and count < k:
next_temp = current.next
current.next = section_prev
section_prev = current
current = next_temp
count += 1
# 连接已反转部分
if prev:
prev.next = section_prev
else:
head = section_prev
section_start.next = current
prev = section_start
reverse = False
else:
# 跳过k个节点
count = 0
while current and count < k:
prev = current
current = current.next
count += 1
reverse = True
return head
4. 特殊场景反转
4.1 反转链表的前N个节点
python
def reverse_first_n(head, n):
successor = None
def reverse_n(node, count):
nonlocal successor
if count == 1:
successor = node.next
return node
last = reverse_n(node.next, count - 1)
node.next.next = node
node.next = successor
return last
return reverse_n(head, n)
4.2 从末尾开始反转
python
def reverse_from_end(head, k):
# 先找到总长度
length = 0
current = head
while current:
length += 1
current = current.next
# 转换为从头开始的位置
m = length - k + 1
return reverse_between(head, m, length)
5. 性能分析与比较
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 迭代法 | O(n) | O(1) | 通用,最常用 |
| 递归法 | O(n) | O(n) | 代码简洁,栈深度受限 |
| 部分反转 | O(n) | O(1) | 局部操作 |
| K组反转 | O(n) | O(n/k) | 批量处理 |
6. 实战技巧与注意事项
6.1 边界情况处理
- 空链表
- 单节点链表
- 反转位置超出范围
- k值大于链表长度
6.2 调试技巧
python
def print_list(head):
"""打印链表用于调试"""
result = []
current = head
while current:
result.append(str(current.val))
current = current.next
print(" → ".join(result) + " → None")
6.3 常见错误
- 忘记处理头节点的更新
- 指针丢失(在改变next前未保存)
- 循环链表的形成
- 边界条件处理不完整
7. 综合练习
题目:给定链表 1→2→3→4→5→6→7,要求实现:
- 完全反转
- 反转2-5位置
- 每3个一组反转
- 交替每2个节点反转
python
# 测试用例
def create_sample_list():
nodes = [ListNode(i) for i in range(1, 8)]
for i in range(len(nodes)-1):
nodes[i].next = nodes[i+1]
return nodes[0]
# 测试各种反转方法
head = create_sample_list()
print("原链表:")
print_list(head)
print("\n完全反转:")
print_list(reverse_list_iterative(create_sample_list()))
print("\n反转位置2-5:")
print_list(reverse_between(create_sample_list(), 2, 5))
print("\n每3个一组反转:")
print_list(reverse_k_group(create_sample_list(), 3))
总结
单链表反转是算法学习中的重要里程碑。掌握从基础到进阶的各种反转技巧,不仅能够解决链表相关问题,更能培养严谨的编程思维和指针操作能力。建议通过大量练习来熟练掌握这些技巧,并理解每种方法适用的场景。
记住:多画图理解指针变化,多写代码加深印象,这是掌握链表问题的关键!