单链表反转:从基础到进阶的完整指南

单链表反转是数据结构与算法中的经典问题,它不仅考察对链表结构的理解,也考验编程思维和技巧。本文将带你从基础实现到高级应用,全面掌握单链表反转。

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 常见错误

  1. 忘记处理头节点的更新
  2. 指针丢失(在改变next前未保存)
  3. 循环链表的形成
  4. 边界条件处理不完整

7. 综合练习

题目:给定链表 1→2→3→4→5→6→7,要求实现:

  1. 完全反转
  2. 反转2-5位置
  3. 每3个一组反转
  4. 交替每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))

总结

单链表反转是算法学习中的重要里程碑。掌握从基础到进阶的各种反转技巧,不仅能够解决链表相关问题,更能培养严谨的编程思维和指针操作能力。建议通过大量练习来熟练掌握这些技巧,并理解每种方法适用的场景。

记住:多画图理解指针变化,多写代码加深印象,这是掌握链表问题的关键!

相关推荐
与遨游于天地3 小时前
Spring解决循环依赖实际就是用了个递归
java·后端·spring
Python私教3 小时前
用 FastAPI + Pydantic 打造“可验证、可热载、可覆盖”的配置中心
后端
Python私教4 小时前
FastAPI “零手工”路由:自动扫描模块、自动注册路由的工程级实践
后端
用户21411832636025 小时前
Claude Skills 实战指南:3 分钟搞定 PPT、海报与 Logo,AI 办公效率翻倍!
后端
想搞艺术的程序员5 小时前
Go Error 全方位解析:原理、实践、扩展与封装
开发语言·后端·golang
程序定小飞6 小时前
基于springboot的web的音乐网站开发与设计
java·前端·数据库·vue.js·spring boot·后端·spring
舒一笑6 小时前
从手写周报到智能生成:PandaCoder如何让你的工作汇报效率提升10倍
后端·程序员·intellij idea
无名之辈J6 小时前
支付常犯错误
后端