【map的使用——随机链表的复制】用map强关联拷贝与源结点

在这里插入图片描述

1.前言

今天我们来回顾之前一道链表的题目,最近学了map容器,老师讲用map关联拷贝与源结点会很好做,特地记录一下。

2.题目简介

题目链接:LINK
在这里插入图片描述

3.求解思路

首先我们来回顾一下之前是怎么做这道题的:

/**
 * 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;
    }

	struct Node* pcur = head;
    //插入一些复制结点
    while(pcur)
    {
        struct Node* pushback = (struct Node*)malloc(sizeof(struct Node));
        pushback->val = pcur->val;

        pushback->next = pcur->next;
        pcur->next = pushback;

        pcur = pcur->next->next;//调整pcur
    }
    //控制拷贝结点的random
    pcur = head;
    while(pcur)
    {
        //如果原链表的random指向空,那我们新链表也要指向空
        if(pcur->random == NULL)
        {
            pcur->next->random = NULL;
            pcur = pcur->next->next;
            continue;
        }

        pcur->next->random = pcur->random->next;
        pcur = pcur->next->next;
    }

    //把拷贝结点放下来
    pcur = head;
    struct Node* pcurx = head->next;
    struct Node* returnpcurx = pcurx; 

    while(pcur)
    {
        pcur->next = pcur->next->next;
        pcur = pcur->next;

        //最后一个节点
        if(pcurx->next == NULL)
        {
            pcurx->next = NULL;
            break;
        }
        pcurx->next = pcurx->next->next;
        pcurx = pcurx->next;
    }

    //返回
    return returnpcurx;
}

之前的整体思路是这样的:我们依次遍历原链表,顺便拷贝出一个一样的结点紧随其后,使之与原链表成为一条链表。
之后,我们再把这个链表分开,分成原链表和拷贝链表。

我们发现之前的时候要拷贝一个链表,然后费力把这个拷贝链表和原链表融合在一起,然后到最后又拆开。

3.1之前做法虽然麻烦,但是有道理

为啥要复制的时候合成一个链表到最后又拆成为两个呢?这不是纯纯给自己找麻烦吗?是的,现在来看的确很麻烦,但是在当时所掌握的知识上,这种方法却也是无奈之举。

之所以这样合在一起又拆开这样做,是因为题目要求拷贝节点的random指向与原结点指向一致。但是两个一上来分开拷贝,我们虽然知道知道原结点指向的是哪里,但是拷贝结点random的指向我们就不明确了,因为两个random之间没有什么关联性。

为了解决这个问题,当时我们想到了一个方法——算相对位置。就是我们拷贝的时候直接让拷贝链表结点紧随源节点其后,这样我们就用合成一个链表的方式强行让两个链表之间的random结点建立了联系。

等到链接好了random,后面又为了满足题目中的要求,我们又不得不再把两个链表拆开而已。

3.2现在map就可以建立两个结点之间的关联

之前只能通过合成一个链表来实现两个结点之间的random之间的关联性,现在我们可以通过容器map来建立两个结点之间的关联性。

所以我们可以得出下面代码:

4.示例代码

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

//我们使用operator[]的方法来解决这个问题,即利用map
class Solution {
public:
    Node* copyRandomList(Node* head) {
        //建立一个map,方便后序对copy链表和origin链表进行关联
        map<Node*, Node*> nodeMap;
        Node* copyHead = nullptr, *copyTail = nullptr, *cur = head;
        //1.我们先把copy链表整出来,并且顺便把两个链表关联起来
        while(cur)
        {
            if(copyHead == nullptr) //如果是第一个结点,要进行特殊处理
            {
                copyHead = copyTail = new Node(cur->val);
            }
            else //如果不是第一个,则挨个往后链接就行
            {
                copyTail->next = new Node(cur->val);
                copyTail = copyTail->next;
            }

            //关联两个链表
            nodeMap[cur] = copyTail;//这句话的意思是,把cur作为key值插入到map中,并且其V值是copy的对应的结点。

            //继续下一个结点
            cur = cur->next;
        }

       //2.我们第二步来处理random问题
       cur = head;
       Node* copy = copyHead;
        while(cur)
        {
            if(cur->random == nullptr)//如果cur的结点的random部分指向的是空,那么我们对应的copy结点的random部分也要指向空
            {
                copy->random = nullptr;
            }
            else//如果不是指向空
            {
                copy->random = nodeMap[cur->random];//这个地方返回的其实是cur的random对应的copy的结点。因为我们前面做过关联了。
            }
            
            cur = cur->next;
            copy = copy->next;
        }

        return copyHead;
    }
};

在这里插入图片描述


EOF

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值