C语言编程实战:每日一题:随机链表的复制

欢迎来到 s a y − f a l l 的文章 欢迎来到say-fall的文章 欢迎来到say−fall的文章


🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言 🔥专栏: 《C语言从零开始到精通》 《C语言编程实战》 《数据结构与算法》 《小游戏与项目》 💪格言:做好你自己,你才能吸引更多人,并与他们共赢,这才是你最好的成长方式。



文章目录

  • 题目:随机链表的复制
    • 一、思路解析
      • [1. 第一步:原地插入拷贝节点(构建"原节点-拷贝节点"成对结构)](#1. 第一步:原地插入拷贝节点(构建“原节点-拷贝节点”成对结构))
      • [2. 第二步:设置拷贝节点的`random`指针](#2. 第二步:设置拷贝节点的random指针)
      • [3. 第三步:拆分原链表与拷贝链表](#3. 第三步:拆分原链表与拷贝链表)
    • 二、流程图
    • 三、关键
    • 四、代码

题目:随机链表的复制

一、思路解析

该代码采用 "原地复制+拆分" 策略,高效实现复杂链表(每个节点含valnext指针、random指针)的深拷贝,核心优势是 时间复杂度O(n)、空间复杂度O(1)(不考虑目标链表存储空间),具体分3步:

1. 第一步:原地插入拷贝节点(构建"原节点-拷贝节点"成对结构)

  • 遍历原链表的每个节点pcur,为其创建一个拷贝节点NewNode(值与原节点相同,random初始为NULL)。
  • 将拷贝节点插入到原节点的后面 (即NewNode->next = pcur->next,再pcur->next = NewNode)。
  • 最终原链表结构变为:原节点1 -> 拷贝节点1 -> 原节点2 -> 拷贝节点2 -> ... -> 原节点n -> 拷贝节点n -> NULL

2. 第二步:设置拷贝节点的random指针

  • 再次遍历原链表(仅遍历原节点,步长为2:pcur = pcur->next->next)。
  • 对于每个原节点pcur,其拷贝节点是pcur->next
    • 若原节点pcurrandomNULL,则拷贝节点的random也为NULL
    • 若原节点pcurrandom指向原链表中的某节点A,则拷贝节点的random应指向A的拷贝节点(即A->next),这是该方法的核心巧思(利用第一步构建的成对结构,直接通过原节点的random找到拷贝节点)。

3. 第三步:拆分原链表与拷贝链表

  • 原链表的第一个拷贝节点(head->next)即为新链表的头节点Newhead
  • 遍历拷贝链表(步长为2:pcur = pcur->next->next),将拷贝节点的next指针指向下一个拷贝节点(跳过原节点),最终拆分出独立的拷贝链表。
  • 原链表结构在拆分后会恢复(可选,该代码未显式恢复,但不影响拷贝结果)。

二、流程图

是 否 是 否 是 是 否 否 是 否 开始 原链表head是否为NULL? 返回NULL 结束 初始化pcur = head pcur ≠ NULL? 调用BuyNode创建拷贝节点
(val=pcur->val,next=pcur->next) prev = pcur,pcur = pcur->next prev->next = 拷贝节点
(插入原节点后) 重置pcur = head 【步骤1完成:原-拷成对结构】 pcur ≠ NULL 且 pcur->next ≠ NULL? pcopy = pcur->next(获取拷贝节点) pcur->random 是否为NULL? pcopy->random = NULL pcopy->random = pcur->random->next
(指向原random的拷贝节点) pcur = pcur->next->next(跳过拷贝节点) 【步骤2完成:random指针设置完毕】 Newhead = head->next(拷贝链表头)
pcur = Newhead pcur ≠ NULL 且 pcur->next ≠ NULL? pcur->next = pcur->next->next
(跳过原节点,连接下一个拷贝节点) pcur = pcur->next(移动到下一个拷贝节点) 【步骤3完成:链表拆分完毕】 返回Newhead

三、关键

  1. BuyNode函数作用 :封装拷贝节点的创建逻辑,确保拷贝节点的next初始指向原节点的下一个节点,random初始为NULL
  2. random指针设置的核心 :利用"原节点后紧跟拷贝节点"的结构,原节点Arandom指向B,则拷贝节点A'random必然指向B'B->next)。
  3. 拆分逻辑 :拷贝链表的节点在原链表中是"隔一个"存在的,因此只需将每个拷贝节点的next指向其下一个拷贝节点(pcur->next->next)即可拆分出独立的拷贝链表。

四、代码

c 复制代码
typedef struct Node Node;
Node* BuyNode(int x,Node* pcur)
{
    Node* NewNode = (Node*)malloc(sizeof(Node));
    NewNode->val = x;
    NewNode->next = pcur->next;
    NewNode->random = NULL;
    return NewNode;
}
struct Node* copyRandomList(struct Node* head) 
{
    if(head == NULL)
    {
        return NULL;
    }
    Node* pcur = head;
	while(pcur)
    {
        Node* NewNode = BuyNode(pcur->val,pcur);
        Node* prev = pcur;
        pcur = pcur->next;
        prev->next = NewNode;
    }
    pcur = head;
    while(pcur != NULL && pcur->next != NULL)
    {
        Node* pcopy = pcur->next; 
        if(pcur->random == NULL)
        {
            pcopy->random = NULL;
        }
        else
        {
            pcopy->random = pcur->random->next;
        }
        pcur = pcur->next->next;
    }
    Node* Newhead = head->next;
    pcur = Newhead;
    while(pcur!= NULL && pcur->next != NULL)
    {
        pcur->next = pcur->next->next;
        pcur = pcur->next;
    }
    return Newhead;
}

  • 本节完...
相关推荐
拾贰_C35 分钟前
【Python | Anaconda】 python-Anaconda 一些命令使用
开发语言·python
唐·柯里昂7981 小时前
野火鲁班猫5使用正点原子 RTL8188EUS Wifi模块驱动移植(Linux5.10 Debian系统) 解决zsh报错
linux·c语言·mcu·物联网·ubuntu·硬件工程·软件构建
二川bro1 小时前
循环性能提升:Python向量化计算技巧
开发语言·python
TracyCoder1231 小时前
大白话讲Java NIO
java·开发语言·nio
potato_may1 小时前
C++ 发展简史与核心语法入门
开发语言·c++·算法
老鱼说AI1 小时前
算法基础教学第二步:数组(超级详细原理级别讲解)
数据结构·神经网络·算法·链表
m5655bj1 小时前
通过 C# 将 RTF 文档转换为图片
开发语言·c#
魂梦翩跹如雨1 小时前
P8615 [蓝桥杯 2014 国 C] 拼接平方数——Java解答
java·c语言·蓝桥杯