代码随想录【链表】---->反转链表、两两交换链表中的节点

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:个人认为如果一个题目会改变头节点的地址,那么这道题可以使用虚拟头节点的方式来完成,因为通过虚拟头节点我们最终只需要返回虚拟头节点的指针域,不需要在意修改链表后的头节点地址
这道题将链表两两节点交换,所以原先的头节点一定会成为修改后链表的中间节点,而原先的中间节点最后一定会成为新链表的头节点,所以对这道题而言头节点的地址改变了,所以可以使用虚拟头节点

现在我们来看一下具体过程

  1. 交换前两个节点
    在这里插入图片描述
    交换后链表变成这个样子
    在这里插入图片描述
  2. 继续交换后面的元素,让cur指向先前cur的后两个节点,重复过程1
  3. 直到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;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_74278159/article/details/130045628