1,题目
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
2,代码
题解
题目要反转链表,可以通过迭代(双指针)和递归来做,这里的双指针不是用于判断链表是否有环的快慢指针,而是普通的双指针。
方法一:迭代(双指针)
具体操作
分别定义两个均指向空的指针 (pre/next);
next 用于记录当前节点的下一个节点(当前节点与当前节点的下一个节点之间连接断开前,先保存当前节点的下一个节点,防止断开后找不到当前节点后面的节点);
pre 用于在改变当前节点指向之前,记录当前节点;
在头节点不为空的情况下,遍历链表(遍历过程中,改变 head/pre/next 节点的指向)。
注意点:
链表是空链表;
链表只有一个节点,即头节点。
struct ListNode* reverseList(struct ListNode* head){
/* 特殊判断 */
if (head == NULL || head->next == NULL) {
return head;
}
struct ListNode* pre = NULL;
struct ListNode* next = NULL;
while (head != NULL) {
next = head->next;
head->next = pre;
pre = head;
head = next;
}
return pre;
}
// 想要代码行数少一点的话,就这样,同样适合空链表或者只有一个节点的链表
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* pre = NULL;
while (head != NULL) {
struct ListNode* next = head->next;
head->next = pre;
pre = head;
head = next;
}
return pre;
}
方法二:递归
链表具有天然的递归性。
一个链表例如 1->2->3->4->5->NULL,可以看成头节点(节点值为 1 的节点)后面挂接一个更短的链表(缺少节点值为 1 的节点,以节点值为 2 的节点为头节点) 1->更短的链表,依次类推。如下如示:
这样的话,就可以先翻转头节点后面挂接的链表,然后把翻转后的链表的后面再挂接头节点,这样就实现了链表的翻转。
递归结束条件:
节点是空节点;
当前只有这一个节点,无需再翻转。
struct ListNode* reverseList(struct ListNode* head){
/* 特判 */
if (head == NULL || head->next == NULL) {
return head;
}
/* 翻转头节点(节点值为 1 的节点) 后面挂接的链表(以节点值为 2 的节点作为头节点) */
/* 翻转之后变成 5->4->3->2 */
struct ListNode *node = reverseList(head->next);
/* 将头节点(节点值为 1 的节点)挂接在翻转之后的链表的后面(也就是节点值为 2 的节点的后面) */
head->next->next = head;
/* 将尾节点的下一节点置空 */
head->next = NULL;
return node;
}