解题思路:
-
为什么不能直接复制一个新链表:因为结点的指针域中不仅有直接后继,还有一个随机指针。直接的挨个复制一个新链表会导致新链表的结点中的随机指针指向原链表中的元素。
-
如何将对应关系一并复制:在每个结点的后方克隆一个结点,然后将克隆的所有结点从新组链接成链表。随机指针通过原链表的随机指针的值指向其下一个元素即可表达。
图示:
-
值为1的结点中随机指针指向值为4的结点。 相应克隆的结点a中随机指针也应该指向d的结点。
-
如此就可以通过在指针后克隆一个结点,通过原链表的对应关系来获得新链表之间对应的关系。
struct Node {
int val;
struct Node *next;
struct Node *random;
};
struct Node* copyRandomList(struct Node* head) {
//1、如果传过来的head链表为NULL ,直接将其返回。
if(!head) return head;
//该步骤可以理解为,为了避免head链表的头指针找不到。
struct Node* cur = head;
//2、克隆结点
while (cur){
//动态创建一个结点,为结点中的变量赋初值。
struct Node* copyNode = (struct Node*)malloc(sizeof(struct Node));
copyNode->random = NULL;
copyNode->next = NULL;
copyNode->val = cur->val;
//此步骤和下一步骤是将copyNode结点放到链表中,
//将copyNode结点的直接后继指向cur的直接后继
copyNode->next = cur->next;
copyNode->random = cur->random;
//将cur结点的直接前继指向copyNode
cur->next = copyNode;
// 将cur指针往后移动一个结点
cur = copyNode->next;
}
//3、拆分结点
/*
思路:
将克隆链表和原链表分离,同时将原链表随机指针的逻辑关系映射到克隆链表中。
*/
cur = head;
//将copyListNode 结点指向克隆的第一个结点作为头结点。
struct Node* copyListNode = head->next;
//拆分开始
while (cur){
/*
定义两个结点,分别含义:
copyNode : 获取当前结点的下一个结点(该节点的克隆结点)
next : 获取原链表中当前结点的下一个结点
*/
struct Node* copyNode = cur->next;
struct Node* next = copyNode->next;
// 因为题目中允许随机指针可以为NULL,也防止解引用该指针值为NULL导致的内存访问错误。
if(copyNode->random)
//如果random不会NULL,将原链表中的对应关系映射到克隆链表节点上
copyNode->random = cur->random->next;
//判断原链表中cur结点的下一个节点是否为最后一个结点。
if (next){
//如不是,则将克隆链表关联起来。
copyNode -> next = next->next;
}
else{
//如是,则将该克隆节点的next结点为NULL
copyNode->next = NULL;
}
//原指针指针后移一个结点。
cur = next;
}
return copyListNode;
}