文章目录
- 206. 反转链表
- 思路
- 双指针实现
- 递归写法
- 24. 两两交换链表中的节点
- 思路
- 代码实现
206. 反转链表
题目LeetCode206. 反转链表
思路
翻转链表实际上只需要将每一个节点的指针域
指向前一个节点即可,原来第一个节点的指针域指向NULL指针
原头节点是1,翻转后的头节点是5,链表翻转仅仅将链表每一个节点的指针域的指向改变了
具体的翻转过程(纠正:动图中应该先移动pre,再移动cur)
- 首先定义了两个指针cur、pre,每次另cur指针指向节点的指针域指向pre指针指向的节点。翻转完一组元素后将pre和cur指针分别向后挪动一个节点
- 直到cur指针变为NULL指针,此时链表翻转完成,pre变为头结点指针,return pre
注意:
- pre指针一开始应该是NULL,为了让第一个节点的指针域指向NULL指针
- cur指针指向下一个节点时应该先将下一个节点的地址保存起来,因为cur指向的节点即进行翻转
接下来就是代码实现了,下面介绍双指针和递归两种代码实现,一定要在理解了双指针的基础上再去理解递归,因为递归代码比较简短、晦涩难懂,但是核心思路和双指针版本是一模一样的
双指针实现
//双指针
struct ListNode* reverseList(struct ListNode* head){
typedef struct ListNode ListNode;
ListNode* cur = head;
//pre指针为NULL是为了让第一个节点翻转为尾节点
ListNode* pre = NULL;
//cur为NULL时结束循环,pre为翻转后的头节点
while (cur)
{
ListNode* tmp = cur->next;//将当前节点的下一个节点存起来
cur->next = pre;//反转节点
pre = cur;//pre指针指向下一个节点
cur = tmp;//cur指针之下下一个节点
}
//返回新的头节点
return pre;
}
递归写法
//递归写法
typedef struct ListNode ListNode;
ListNode* reverse(ListNode* pre, ListNode* cur)
{
/*
while (cur)
return pre
这个步骤等价于下面*/
if (cur == NULL) return pre;
//反转
ListNode* tmp = cur->next;
cur->next = pre;
/*
pre = cur;
cur = tmp;
这个步骤等价于下面*/
return reverse(cur, tmp);
}
struct ListNode* reverseList(struct ListNode* head){
return reverse(NULL, head);
}
递归写法中的reverse函数是将cur指向节点的指针域指向pre指向的节点,所以每次翻转完一个元素后,需要接着翻转下一个元素直到翻转完整个链表。翻转下一个元素直接将cur作为形参传给pre,将tmp(翻转前cur的下一个节点)传给cur
24. 两两交换链表中的节点
题目LeetCode24. 两两交换链表中的节点
思路
PS:个人认为如果一个题目会改变头节点的地址,那么这道题可以使用虚拟头节点的方式来完成,因为通过虚拟头节点我们最终只需要返回虚拟头节点的指针域,不需要在意修改链表后的头节点地址
这道题将链表两两节点交换,所以原先的头节点一定会成为修改后链表的中间节点,而原先的中间节点最后一定会成为新链表的头节点,所以对这道题而言头节点的地址改变了,所以可以使用虚拟头节点
现在我们来看一下具体过程
- 交换前两个节点
交换后链表变成这个样子
- 继续交换后面的元素,让cur指向先前cur的后两个节点,重复过程1
- 直到cur->next(偶数个节点)或者cur->next->next(奇数个节点)为空时停止循环
注意:
- 执行步骤二前需要将cur指向的后面一个节点地址存起来为了可以让cur的后面第二个节点指向cur后面第一个节点
- 执行步骤三需要将cur指向后面的第三个节点地址存起来为了可以让cur后面第一个节点指向cur后面第三个节点
代码实现
struct ListNode* swapPairs(struct ListNode* head){
typedef struct ListNode ListNode;
//虚拟头节点的创建
ListNode* dummyHead = (ListNode*)malloc(sizeof(ListNode));
dummyHead->next = head;
ListNode* cur = dummyHead;
//考虑奇数和偶数个节点
while (cur->next != NULL && cur->next->next != NULL)
{
//将cur后面第1、3个节点的地址存起来
ListNode* tmp1 = cur->next;
ListNode* tmp2 = cur->next->next->next;
//步骤一
cur->next = cur->next->next;
//步骤二
cur->next->next = tmp1;
//步骤三
tmp1->next = tmp2;
//cur移动两位、准备下一位的交换
cur = cur->next->next;
}
return dummyHead->next;
}