反转链表是指改变单链表中节点之间的连接关系,使得原本的正向顺序变为反向顺序。以下是反转单链表的常见方法:
一. 迭代法
迭代法反转链表的流程:使用三个指针,通常命名为 prev、current 和 next:
- 初始化 prev 指针为空,current 指针指向头节点;
- 遍历链表,每次迭代过程中:
- 将 current 节点的下一个节点暂存到 next 指针;
- 修改 current 节点的 next 指针使其指向 prev 节点;
- prev 和 current 指针都向前移动一步,即将 current 更新为原来的 next,prev 更新为 current;
- 迭代结束后,prev 指针将指向新的头节点。
下面是具体的代码实现:
# 定义链表节点类
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverseList_iteratively(head):
"""
迭代法反转链表
:param head: ListNode,链表的头节点
:return: ListNode,反转后的链表头节点
"""
# 初始化前驱节点为None
prev = None
# 当前节点开始为头节点
current = head
# 只要当前节点不为空
while current is not None:
# 保存当前节点的下一个节点
next_node = current.next
# 将当前节点的next指针指向其前驱节点
current.next = prev
# 更新前驱节点和当前节点,准备处理下一个节点
prev = current
current = next_node
# 循环结束后,prev将是反转后的新头节点
return prev
# 创建链表示例
head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)
head.next.next.next.next = ListNode(5)
# 反转链表
reversed_head = reverseList_iteratively(head)
二. 递归法
- 设定递归函数,传入当前节点作为参数:
- 当前节点为空或只有一个节点时,直接返回该节点(此时无需反转);
- 否则,递归调用函数处理下一个节点,得到反转后的下一个节点;
- 然后修改当前节点的 next 指针,使之指向反转后返回的节点;
- 最后返回当前节点作为新的子链表的头节点。
请注意,在递归版本中,由于递归调用机制,函数会自动回溯并逐步恢复链表节点的next指针指向,最后返回反转后的头节点。迭代法则是通过循环来逐步更改每个节点的next指针,直到整个链表反转完成。
下面是具体的代码实现:
def reverseList_recursively(head):
"""
递归法反转链表
:param head: ListNode,链表的头节点
:return: ListNode,反转后的链表头节点
"""
# 递归终止条件:空节点或者只有一个节点的情况,直接返回该节点
if not head or not head.next:
return head
# 递归调用,反转后续链表
new_head = reverseList_recursively(head.next)
# 逆转当前节点的next指针,使它指向其前一个节点
head.next.next = head
# 断开当前节点与之前序列的连接
head.next = None
# 返回新链表的头节点
return new_head
三. 头插法(创建新链表)
- 创建一个新的空节点作为新链表的头节点;
- 遍历原链表,对于每个节点,将其从原链表摘下并插入到新链表的头部(利用链表的头插法特性);
- 完成遍历后,新链表的头节点即为原链表的最后一个节点,也就是反转后的头节点。
这种方式虽然可以实现反转,但并不是严格意义上的原地反转,因为它创建了新的链表结构。
下面是具体的代码实现:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverseList_headInsertion(head):
# 创建一个虚拟头节点
dummy = ListNode(0)
# 新链表的当前节点始终是dummy节点
curr = dummy
# 遍历原链表
while head:
# 保存当前节点的下一个节点
next_node = head.next
# 将当前节点插入到新链表的头部
head.next = curr.next
curr.next = head
# 移动到原链表的下一个节点
head = next_node
# 返回新链表的实际头节点(即原链表的尾节点)
return dummy.next
四. 原地反转法
- 不创建新链表,直接在原链表上修改节点间的指向关系。
- 这实际上就是迭代法的一种特殊情况,只是不额外使用 prev 指针,而是直接更新节点间的 next 指针。
下面是具体的代码实现:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def reverseList(head):
prev = None
current = head
while current is not None:
next_temp = current.next # 保存当前节点的下一个节点
current.next = prev # 将当前节点的next指针指向前一个节点
prev = current # 更新前一个节点为当前节点
current = next_temp # 移动到下一个节点
return prev # 返回新的头节点
# 示例使用:
# 创建一个链表: 1 -> 2 -> 3 -> 4 -> 5
head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)
head.next.next.next.next = ListNode(5)
# 反转链表
new_head = reverseList(head)
# 遍历查看反转后的链表: 5 -> 4 -> 3 -> 2 -> 1
while new_head is not None:
print(new_head.val)
new_head = new_head.next
这段代码首先定义了一个ListNode类来表示链表节点,然后实现了reverseList函数用于原地反转链表。在反转过程中,我们只修改了链表中节点的next指针,没有创建任何新的节点,所以这种方法的空间复杂度是O(1)。