一句话总结:
反转单链表就像把一列火车倒着开——原本车头变车尾,每节车厢都要调头指向前面的车厢!
一、迭代法(步步为营)
核心思路: 用三个指针边走边改方向,像翻链条一样逐个反转。
Kotlin 代码:
class Node(var data: Int, var next: Node? = null)
fun reverseListIterative(head: Node?): Node? {
var prev: Node? = null // 前一个节点(初始为空)
var curr = head // 当前节点(从头开始)
while (curr != null) {
val nextTemp = curr.next // 暂存下一个节点(防止断链)
curr.next = prev // 调头指向前一个
prev = curr // 前节点前进
curr = nextTemp // 当前节点前进
}
return prev // 最后prev就是新头
}
图解过程:
原链表:1 → 2 → 3 → null
反转步骤:
- prev=null, curr=1 → 暂存2,1指向null → prev=1, curr=2
- 暂存3,2指向1 → prev=2, curr=3
- 暂存null,3指向2 → prev=3, curr=null
结果:3 → 2 → 1 → null
二、递归法(从尾到头)
核心思路: 递归到链表末端,返回时逐个反转指针方向。
Kotlin 代码:
fun reverseListRecursive(head: Node?): Node? {
if (head?.next == null) return head // 终止条件:只剩一个节点
val newHead = reverseListRecursive(head.next) // 递归到最深处
head.next?.next = head // 反转指向(让后一个节点指回自己)
head.next = null // 断开原方向
return newHead
}
图解过程:
递归到3时返回 → 处理2:3.next = 2 → 2.next = null → 处理1:2.next = 1 → 1.next = null
最终链表:3 → 2 → 1 → null
三、性能对比
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 迭代法 | O(n) | O(1) | 常规使用,省内存 |
| 递归法 | O(n) | O(n) | 代码简洁,小链表 |
四、测试用例
fun main() {
// 创建链表 1 → 2 → 3
val node3 = Node(3)
val node2 = Node(2, node3)
val node1 = Node(1, node2)
// 反转并打印
var newHead = reverseListIterative(node1)
printList(newHead) // 输出:3 → 2 → 1 → null
// 递归法测试(需重新构建链表)
val node3Rec = Node(3)
val node2Rec = Node(2, node3Rec)
val node1Rec = Node(1, node2Rec)
newHead = reverseListRecursive(node1Rec)
printList(newHead) // 输出同上
}
// 辅助打印函数
fun printList(head: Node?) {
var curr = head
while (curr != null) {
print("${curr.data} → ")
curr = curr.next
}
println("null")
}
五、常见错误
-
断链忘暂存:直接修改
curr.next前未保存next节点// 错误写法! while (curr != null) { curr.next = prev // 此时curr.next已经被覆盖,无法继续遍历 prev = curr curr = curr.next // 这里curr.next已经是prev了,导致死循环 } -
递归忘记终止条件:导致无限递归栈溢出
六、终极口诀
反转链表两板斧,
迭代递归任你选。
三个指针步步移,
递归到底再回头!
小数据用递归爽,
大数据迭代保平安! 🔄