深度拷贝一个结点中有随机指针的链表

结点类型:

//Definition for singly-linked list with a random pointer.
struct RandomListNode {
    int label;
    struct RandomListNode *next;
    struct RandomListNode *random;
};
 

要求返回这个链表的深度拷贝。 

(图片中省略了每个结点之间的next连线)

random指针会指向任意其他结点,也可以指向自己结点,甚至可以为NULL。

算法分析:

(1)开始的思考:

首先拷贝一个链表非常简单,只需遍历一个链表然后将数据拷贝到新链表即可,但由于random的随机性问变增加了难度,首先能够想到的就是记录并保存每一个结点random的指向,然后在新的链表中一一实现。但是,若random指向之前的结点,在单链表中查找之前的结点是非常困难的一件事,只能再次从头结点开始查找,时间复杂度会很高。因此这样固然是不可以的,时间复杂度会很高,算法的实习也会相当困难。我们只能考虑新的算法。

(2)新的算法:

因为这是单链表,单链表在找寻一个结点的下一个结点时会很简单,但在查找其他位置的结点时会比较麻烦,尤其是查找之前的结点。我们根据单链表这一特性思考,如果在查找random时可以像查找一个结点的下一个结点那样简单,问题就解决了。

所以,我们可以在每一个结点之后拷贝一个与本结点相同的新结点,

(图中蓝色结点为新结点,每个结点之间的链接省略)

这样,新结点中的random只需指向原结点的random->next,新的链表的random便链接完成,过程中注意判断空指针空指针不能进行解引用操作。

最后只需将原链表与新链表分离即可。分离时新链表要考虑链表中有结点的情况,此时只需尾插即可;也要考虑链表中没有结点的情况,此时要插入的结点便为新链表的头结点。也可以新建一个头结点,此时只需尾插即可,不用分情况讨论。

此时便完成了一个深拷贝

实现代码如下:

/**
 * Definition for singly-linked list with a random pointer.
 * struct RandomListNode {
 *     int label;
 *     struct RandomListNode *next;
 *     struct RandomListNode *random;
 * };
 */
struct RandomListNode *copyRandomList(struct RandomListNode *head) {
    struct RandomListNode *cur = head;
    struct RandomListNode *next = head;
    struct RandomListNode *NewList = NULL;
    struct RandomListNode *NewHead = (struct RandomListNode *)malloc(sizeof(struct RandomListNode));
    
    //在每个结点后链接一个新结点
    while (cur){
        next = cur->next;
        NewList = (struct RandomListNode *)malloc(sizeof(struct RandomListNode));
        cur->next = NewList;
        NewList->next = next;
        cur = next;
    }
    
    //将每个新生成的结点拷贝为与前一个完全相同的结点
    cur = head;
    if (cur){
        next = cur->next;
    }
    while (cur){
        next->label = cur->label;
        if (cur->random){
            next->random = cur->random->next;
        }
        else{
            next->random = NULL;
        }
        cur = next->next;
        if (cur){
                next = cur->next;
        }
    }
    
    //将新生成的结点断开生成一个新的链表并还原原链表
    cur = head;
    if (cur){
        next = cur->next;
    }
    NewList = NewHead;
    while (cur){
        cur->next = next->next;
        NewList->next = next;
        cur = cur->next;
        if (cur){
            next = cur->next;            
        }
        NewList = NewList->next;
    }
    
    NewList = NewHead->next;
    free(NewHead);
    NewHead = NULL;
    return NewList;    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值