目录
1. 反转链表
1.1 题目描述
1.2 思路一:反转指针
1.3 思路二:头插到新链表
1.4 往期回顾
1. 反转链表
原题链接:
剑指 Offer 24. 反转链表 - 力扣(LeetCode)
https://leetcode.cn/problems/fan-zhuan-lian-biao-lcof/
1.1 题目描述
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
1.2 思路一:反转指针
看到这道题之后我们会很自然地想到只要将链接节点的指针反转过来,改变原来链表的方向,然后再从头到尾遍历输出到数组即可。
我们可以维护三个指针prev,cur,next,prev初始化为空指针,cur初始化为头结点的指针,next初始化为头结点的下一个节点的指针。
为什么要这么做呢?维护prev的目的是方便反转节点指针后,指向新的节点或者NULL,维护cur的目的就是遍历整个的链表,维护next的目的是方便找到cur的下一个节点,因为一旦反转了指针不用一个指针提前找到cur的下一个节点,就真的找不到下一个节点了!
反转一次之后,把cur给给prev,把next给给cur,next的下一个节点的指针给给next,以此类推直到cur为空指针。我们就完成了反转链表。最后将新的头结点prev赋值给原链表的头结点(见下图)。
//直接反转指针
struct ListNode* reverseList(struct ListNode* head){
//对输入做合法性判断
if(head == NULL || head->next == NULL)
{
return head;
}
//初始化cur,prev
struct ListNode* cur = head, *prev = NULL;
while(cur != NULL)
{
//逐步反转指针
struct ListNode* next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}
1.3 思路二:头插到新链表
我们可以重新创建一个新的链表,为了方便插入新的节点,我们创建一个带哨兵位的头结点的链表。
我们遍历原来的链表,将每个节点的值头插到我们创建的新的链表中,如此便达到了反转链表的效果。C语言嘛,我们需要自己写一下头插函数,创建新的节点的函数。
创建一个带哨兵位的头节点的链表仅仅是为了方便头插函数的书写,所以当返回结果时,需要返回头结点的下一个节点。
//开辟新节点
struct ListNode* buyNewNode(int x)
{
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
//初始化开辟的新节点
newNode->next = NULL;
newNode->val = x;
return newNode;
}
//头插函数
void listPushFront(struct ListNode* head, int x)
{
//记录下一个节点
struct ListNode* next = head->next;
struct ListNode* newNode = buyNewNode(x);
//连接
head->next = newNode;
newNode->next=next;
}
struct ListNode* reverseList(struct ListNode* head)
{
//对输入做合法性判断
if(head == NULL || head->next == NULL)
{
return head;
}
//创建一个带哨兵位的头结点的链表
struct ListNode* phead = buyNewNode(0);
//用cur指针遍历原链表,将得到的值头插到新链表
struct ListNode* cur = head;
while(cur != NULL)
{
listPushFront(phead, cur->val);
cur = cur->next;
}
//返回结果
return phead->next;
}
1.4 往期回顾
面试题23:链表中环的入口节点
http://t.csdn.cn/QxBYN
http://t.csdn.cn/QxBYN面试题22:链表中的倒数第 k 个节点
http://t.csdn.cn/rQc1x
http://t.csdn.cn/rQc1x