复制带随机指针的链表

举报
芒果_Mango 发表于 2022/04/30 22:55:32 2022/04/30
【摘要】 大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流作者简介:CSDN C/C++领域新星创作者https://blog.csdn.net/chuxinchangcun?type=blog掘金LV3用户 https://juejin.cn/us...

大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:


题目要求

链接:138. 复制带随机指针的链表 - 力扣(LeetCode) (leetcode-cn.com)


image-20220209223920608

random指针指向自己也可以


思路:

思路1:直接拷贝原链表

image-20220209223931827

原来的结点和复制出的结点没有关系 复制的结点是malloc出来的,二者没有直接的关系

如果需要找到拷贝结点对应的random结点->需要找到原来链表对应结点的random结点的距离k,然后对应指针走k步

每个结点都要如此!复杂


思路2: 时间复杂度:O(n)

  • 1.复制结点,插入到原结点和下一个结点之间

    • image-20220209223946477

代码:

   //1.拷贝结点,插入到原结点后面
    struct Node* cur = head;
    //cur遍历原链表,当cur为空时,说明已经遍历完原来的整个链表
    while(cur)
    {
        //开辟新节点拷贝cur指向结点的值
        struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
        //拷贝值
        copy -> val = cur -> val;
        //将复制结点插入到原结点和下一个结点之间
        
        //copy链接原来结点的下一个结点,插入copy结点到原结点(cur)后面,
        copy -> next = cur->next;
        //cur指向的结点链接复制结点
        cur -> next = copy;
        //cur指向原来的下一个结点(下一个结点是:copy -> next 结点)
        cur = copy -> next;
    }

image-20220209223954856


写法2:使用指针保存原来的下一个结点,双指针

struct Node* cur = head;
//cur遍历原链表,当cur为空时,说明已经遍历完原来的整个链表
while(cur)
{
    //开辟新节点拷贝cur指向结点的值
    struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
    copy->next = NULL;
    copy->random= NULL;
    copy->val = cur->val;
    
    //将复制结点插入到原结点和下一个结点之间
    struct ListNode* next = cur->next;//保存原来结点的下一个结点
    cur -> next = copy;//将复制结点插入到原结点之后
    copy->next = next;//复制结点链接原来结点的下一个结点
    cur = next;//cur指向原来结点的下一个结点,继续下一轮拷贝
}

image-20220209224008240


  • 2.根据原结点的random,处理复制结点的random

    • image-20220209224017889

代码:

cur重新指向原来链表的头,遍历链表

按照思路2:

拷贝结点的random指针指向的结点,就是原来结点的random结点的下一个结点 因为我们是把拷贝结点,插入到原结点之后,所以就有了这种对应关系!

image-20220209224026777

 //2.根据原结点,处理copy结点的random
    cur = head;
//遍历链表
    while(cur)
    {
        //copy结点在cur指向结点之后
        struct Node* copy = cur->next;
        //如果cur指向的结点的random为NULL(原来结点的random为NULL),则拷贝结点的random也为NULL
        if(cur -> random  == NULL)
        {
            copy -> random = NULL;
        }
        else
        {
            //拷贝结点的random指向的就是cur的random结点的下一个结点
            copy -> random = cur -> random -> next;
        }
        cur = copy->next;
    }

  • 3.将复制结点解下来,恢复原链表的关系

    • image-20220209224044744

代码:

因为要返回拷贝链表的头,所以定义一个头指针

解下来->本质是尾插,为了方便,定义尾指针,可以用哨兵位,也可以不用

  • 定义头尾指针,方便把拷贝结点尾插

  • 保存原来结点的下一个结点(保存cur->next),记为next

  • 把拷贝结点解下来,尾插到新链表

    • 先判断新链表是否为空,如果为空,头尾指针指向现在的拷贝结点
    • 否则:尾指针指向拷贝结点,然后更新尾指针的指向
  • 恢复原来的结点的指向(cur指向的就是原来的结点),cur的next指向next就是恢复指向

  • 迭代往后走,直到把原链表遍历结束

image-20220209224059306

 //3.把拷贝结点解下来,链接成新链表,同时恢复原链表
    //定义头指针和尾指针
    struct Node* copyHead = NULL,*copyTail = NULL;
    //cur遍历原链表
    cur = head;
    while(cur)
    {
        //复制的结点在当前cur指向结点的下一个位置
        struct Node* copy = cur->next;
        //原结点的下一个结点在拷贝结点的next,保存下一个结点
        struct Node* next = copy->next;
        //将拷贝链表解下来
        //最初:链表为空:判断一下
        if(copyTail == NULL)
        {
            copyHead  = copyTail = copy;
        }
        else
        {
            //链表的尾结点链接拷贝结点
            copyTail ->next = copy;
            //更新尾结点
            copyTail = copy;
        }
        //恢复原来结点的next指向
        cur->next = next;
        //cur指向原来结点的下一个结点,迭代往后走
        cur = next;
    }

代码

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */
​
struct Node* copyRandomList(struct Node* head) 
{
    if(head == NULL)
    {
        return NULL;
    }
    //1.拷贝结点,插入到原结点后面
    struct Node* cur = head;
    //cur遍历原链表,当cur为空时,说明已经遍历完原来的整个链表
    while(cur)
    {
        //开辟新节点
        struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
        //拷贝值
        copy -> val = cur -> val;
        //copy链接原来结点的下一个结点,插入copy结点到原结点(cur)后面,
        copy -> next = cur->next;
        cur -> next = copy;//cur指向原来的下一个结点(此时是:copy -> next 结点)
        cur = copy -> next;
    }
    //2.根据原结点,处理copy结点的random
    cur = head;
    while(cur)
    {
        struct Node* copy = cur->next;
        if(cur -> random  == NULL)
        {
            copy -> random = NULL;
        }
        else
        {
            copy -> random = cur -> random -> next;
        }
        cur = copy->next;
    }
    //3.把拷贝结点解下来,链接成新链表,同时恢复原链表
    struct Node* copyHead = NULL,*copyTail = NULL;
    cur = head;
    while(cur)
    {
        struct Node* copy = cur->next;
        struct Node* next = copy->next;
        if(copyTail == NULL)
        {
            copyHead  = copyTail = copy;
        }
        else
        {
            copyTail ->next = copy;
            copyTail = copy;
        }
        
        cur->next = next;
        cur = next;
    }
    return copyHead;
}

\

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。