链表学习检验题目-随机链表的复制

这一题目是非常经典的,可以完美检验链表知识点的掌握情况

题目链接

138. 随机链表的复制 - 力扣(LeetCode)

题目

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

你的代码  接受原链表的头节点 head 作为传入参数。

解题思路和图解

我们看见这个题目的时候首先就是看不懂,有点懵的。其实这都是我们想复杂了、这里你不能来回去追求random指向的节点的哪里,只需要直接进行拷贝就可以

步骤1(考察链表的创建,赋值):

  1. 首先我们需要复制链表节点
  2. 然后我们把赋值的节点里面是数值val放到复制的节点里面,这里是不需要赋值next的,因为你只需要直接进行插入就可以,形成新的长的链表。
  3. 一边复制一边把节点插入到原链表里面形成一个

步骤2(考察链表的逻辑关系):

  1. 此时我们复制val到链表里面并没有复制random也就是随机节点,所以这里我们需要复制随机节点
  2. 首先我们判断这个节点里面的random指向的节点是不是NULL,如果是NULL也就是说明指向空,也就是最后一个节点
  3. 如果不是NULL ,也就是说明,这个节点指向的下一个节点不是NUILL,此时我们需要注意,这里的关键点来了。我们需要让拷贝节点里面的random的地址是原链表的random指向的下一个节点,也就是random的->next,这样我们就达到我们不需要进行指向,直接就把地址拷贝过来。
  4. 意思就是,拷贝链表节点,直接存放下一个节点的random

步骤3(拷贝链表的插入):

  1. 最后一步,很简单,只需要把链表拷贝的节点和原链表分开
  2. 最后返回新链表的头结点

题目代码

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */
 //这里进行重命名一下,后期使用的时候不需要一直写struct
typedef struct Node Node;
Node* copyRandomList(Node* head) 
{
    //创建节点,复制节点,插入节点
    Node* cur = head;
    while(cur)
    {
        //创建节点,并且进行检验
        Node* copy = (Node*)malloc(sizeof(Node));
        if(copy == NULL)
        {
           perror("copyRandomList:copy:error");
           exit(1);
        }
        //复制数值
        copy->val = cur->val;
        //插入链表(这一步,两个不能交换)
        copy->next = cur->next;
        cur->next = copy;
        //遍历
        cur = copy->next;
    }

    //复制random节点
    cur = head;//cur一移动了重新指向头结点
    while(cur)
    {
        Node* copy = cur->next;//找到copy拷贝节点,这里必须是循环里面的,因为每次都需要改变位置
        if(cur->random == NULL)
        {
            copy->random = NULL;
        }
        else
        {
            copy->random = cur->random->next;
        }
        //遍历
        cur = copy->next;
    }

    //取出需要的节点,返回头结点
    cur = head;//cur一移动了重新指向头结点
    Node* copyhead = NULL;Node* copytile = NULL;//创建头结点和尾结点,不创建哨兵位了
    while(cur)
    {
        //这一步已经完成循环移动了,我们只需要每次移动cur就可以完成整体的移动
        Node* copy = cur->next; 
        Node* pure = copy->next;
        if(copytile == NULL)
        {
            copyhead = copytile = copy;
        }
        else
        {
            //进行尾插
            copytile->next = copy;
            copytile = copytile->next;
        }
        cur = pure;
    }
    //返回新链表头结点
    return copyhead;
}

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值