反转链表
题目描述
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
题目来源
思路一、
把链表的的每个链接的方向取反
要使两个结点之间的指针指向反转,看似用两个变量足矣,直接让后一个结点指向前一个结点。但是仔细思考后发现并没有那么简单,我们如果直接让后一个结点指向前一个结点,那么后一个结点所指向的再后面一个结点的位置就无从知晓了。所以,我们还得定义3个指针变量:n1,n2,n3 。
1)初始条件
n1=NULL
n2=head
n3=head->next
2)翻转核心逻辑
1.n3 用来记录n2下个结点,
2.改变n2的指针域,之前指向n3,现在指向n1,
![在这里插入图片描述](https://img-blog.csdnimg.cn/4d4c05a9f475453385dfdde5a19c4e97.png
3)迭代条件(n1,n2,n3向后挪动一位)
n1=n2
n2=n3;
n3=n3->next;
4)结束条件
n2==NULL;
代码的实现一、
// 方法一、
// 链表换方向
struct ListNode* reverseList2(struct ListNode* head) {
//如果链表没结点或只有一个结点,无需处理,返回头指针
if (head == NULL || head->next == NULL)
{
return head;
}
struct ListNode* n1 = NULL;
struct ListNode* n2 = head;
struct ListNode* n3 = head->next;
while (n2)
{
n2->next = n1;
n1 = n2;
n2 = n3;
if (n3)
n3 = n3->next;
}
return n1;
}
思路二、头插法
创建一个新链表头,然后把旧链表的结点,挨个挨个头插到新链表中
1)初始化
新链头 newhead
cur 指向头插结点
next 记录下一个头插结点
cur=head;
newhead=NULL;
next=head->next;
2)翻转逻辑
让cur的指针域指向新链头
3)迭代条件
newhead=cur
cur=next
next=next->next;
注意:在迭代时,如果next==NULL,接下来next无需迭代了
4)结束条件
cur==NULL;
代买实现二、
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL||head->next==NULL)
{
return head;
}
// 初始化
struct ListNode *cur=head;
struct ListNode *newhead=NULL;
struct ListNode *next=head->next;
//
while(cur)
{
cur->next=newhead;
newhead=cur;
cur=next;
if(next!=NULL)
next=next->next;
}
return newhead;
}
思路三、
两两交换数据域,
初始化:
头和尾
通过计算链表的长度,就可以用循环来控制,尾
方法很简单,但是写起来不那么容易
struct ListNode* reverseList1(struct ListNode* head) {
if (head == NULL)
{
return head;
}
int count2 = 0;
int count3 = 0;//3
int count = 0;//0
//计算链表长度
struct ListNode* tail = head;
while (tail->next)
{
tail = tail->next;
count++;
}
int count4 = count / 2 + 1;
while (count4--)
{
struct ListNode* cur = head;
struct ListNode* tail2 = head;
//计算左边链表
count2 = count3;
while (count2--)
{
cur = cur->next;
}
count3++;
// 计算右边链表
int tail2i = count;
while (tail2i--)
{
tail2 = tail2->next;
}
count--;
if (tail2 == cur || cur->next == NULL)
{
return head;
}
int tmp = cur->val;
cur->val = tail2->val;
tail2->val = tmp;
}
return head;
}