目录
题目链接与介绍
解析题意
1、简单的来说其实就是,现在有一个单链表,它不仅有next指针指向后边的结点。还有random指针指向一个随机的结点。
2、现在要对其进行“深拷贝”,注意:这里是深拷贝,也就是说要复制一个一模一样的链表,与题目所给的链表一模一样,也就是需要重新创建新结点,然后进行遍历链接工作。
3、新链表与旧链表是不能有指向关系的,也就是他们是两个独立的链表,并且对应的结点中的val值还需相同。
当我们已经明白了题意之后,就可以对其进行相应步骤的操作了。
具体操作步骤
步骤一:
主要进行创建新结点copy(并给旧结点赋上对应新结点的值),在遍历新链表与旧链表的同时。并将新结点与旧结点进行链接,还需给对应新结点赋上旧结点的值。
具体图解:
具体代码:
// 步骤一
// 主要进行创建新结点copy(并给旧结点赋上对应新结点的值),并将新结点与旧结点进行链接
// 给cur赋初值便于进行旧表结点的操作
struct Node* cur=head;
// 开始遍历
while(cur)
{
// 定义一个next便于进行链接
struct Node* next = cur->next;
// 创建新结点copy,为新链表做基础
struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
// 给新结点赋上对应旧结点的值
copy->val=cur->val;
// 链接操作
// 旧结点链接新结点
cur->next=copy;
// 新结点链接旧结点
copy->next=next;
// 继续遍历
cur=next;
}
步骤二:
目的是为了解决新结点random的链接问题。
如果新结点对应旧结点的random为空那么它的random也是空。
若不为空,则刚好指向对应新结点random的next(原因是此时旧结点的next恰好指向的就是相对应的新结点!)。
具体图解:
具体代码:
// 步骤二
// 目的是为了解决新结点random的链接问题
// 重新赋值,重新遍历
cur=head;
// 遍历操作
while(cur)
{
// 第一次进入循环是给copy赋初值
// 接下老就是遍历新结点的意思了
struct Node* copy=cur->next;
// 如果对应旧结点的random!=NULL
// 然后根据旧结点的next刚好就是对应的新结点
// 让新结点的random=旧结点的random的next
if(cur->random!=NULL)
{
copy->random=cur->random->next;
}
// 如果cur->random是一个NULL
// 那么毋容置疑copy->random一定是个NULL
else
{
copy->random=NULL;
}
// cur继续向后遍历,由于cur之前的next已经被改变
// 所以只能通过copy进行向后遍历
cur=copy->next;
}
步骤三:
去掉新链接,恢复旧链接 。
将所有新结点与旧结点的链接给去掉,恢复旧链表原本的链接,完成新结点的next链接。
具体图解:
具体代码:
// 步骤三
// 去掉新链接,恢复旧链接
// 继续赋初值来进行遍历
cur=head;
// 定义两个结点,一个作为新链表的头结点
// 一个作为新链表的尾结点
// 当然,尾结点可以通过遍历进行链接操作
struct Node* copyHead=NULL;
struct Node* copyTail=NULL;
// cur进行遍历操作
while(cur)
{
// 第一次进入循环是给copy赋初值
// 接下老就是遍历新结点的意思了
struct Node* copy=cur->next;
// 为了恢复旧链接,需要找到cur的next
// 因此只能通过copy去找
struct Node* next=copy->next;
// 第一次进入循环copyTail肯定是NULL
// 那么将copyHead和copyTail先赋初值copy
// 因为copy就是新链表的头
if(copyTail==NULL)
{
copyTail=copyHead=copy;
}
// 如果不是第一次进入循环,那么就要开始链接新结点了
// 第二次再进来之后copyTail还是上一次copy的位置
// 然而copy已经变成cur->next了也就是相对于新链表的
// 下一个位置,因此直接copyTail->next=copy进行链接操作
// 然后让copyTail也向后遍历copyTail=copy
else
{
copyTail->next=copy;
copyTail=copy;
}
// 链接旧结点
cur->next=next;
// 让旧结点向后遍历
cur=next;
}
// 由于刚开始copyHead就是新链表的头,然后就没有再改变
// 因此copyHead就是新链表的头,直接返回即可
return copyHead;
完整代码
/**
* Definition for a Node.
* struct Node {
* int val;
* struct Node *next;
* struct Node *random;
* };
*/
struct Node* copyRandomList(struct Node* head)
{
// 步骤一
// 主要进行创建新结点copy(并给旧结点赋上对应新结点的值),并将新结点与旧结点进行链接
// 给cur赋初值便于进行旧表结点的操作
struct Node* cur=head;
// 开始遍历
while(cur)
{
// 定义一个next便于进行链接
struct Node* next = cur->next;
// 创建新结点copy,为新链表做基础
struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
// 给新结点赋上对应旧结点的值
copy->val=cur->val;
// 链接操作
// 旧结点链接新结点
cur->next=copy;
// 新结点链接旧结点
copy->next=next;
// 继续遍历
cur=next;
}
// 步骤二
// 目的是为了解决新结点random的链接问题
// 重新赋值,重新遍历
cur=head;
// 遍历操作
while(cur)
{
// 第一次进入循环是给copy赋初值
// 接下老就是遍历新结点的意思了
struct Node* copy=cur->next;
// 如果对应旧结点的random!=NULL
// 然后根据旧结点的next刚好就是对应的新结点
// 让新结点的random=旧结点的random的next
if(cur->random!=NULL)
{
copy->random=cur->random->next;
}
// 如果cur->random是一个NULL
// 那么毋容置疑copy->random一定是个NULL
else
{
copy->random=NULL;
}
// cur继续向后遍历,由于cur之前的next已经被改变
// 所以只能通过copy进行向后遍历
cur=copy->next;
}
// 步骤三
// 去掉新链接,恢复旧链接
// 继续赋初值来进行遍历
cur=head;
// 定义两个结点,一个作为新链表的头结点
// 一个作为新链表的尾结点
// 当然,尾结点可以通过遍历进行链接操作
struct Node* copyHead=NULL;
struct Node* copyTail=NULL;
// cur进行遍历操作
while(cur)
{
// 第一次进入循环是给copy赋初值
// 接下老就是遍历新结点的意思了
struct Node* copy=cur->next;
// 为了恢复旧链接,需要找到cur的next
// 因此只能通过copy去找
struct Node* next=copy->next;
// 第一次进入循环copyTail肯定是NULL
// 那么将copyHead和copyTail先赋初值copy
// 因为copy就是新链表的头
if(copyTail==NULL)
{
copyTail=copyHead=copy;
}
// 如果不是第一次进入循环,那么就要开始链接新结点了
// 第二次再进来之后copyTail还是上一次copy的位置
// 然而copy已经变成cur->next了也就是相对于新链表的
// 下一个位置,因此直接copyTail->next=copy进行链接操作
// 然后让copyTail也向后遍历copyTail=copy
else
{
copyTail->next=copy;
copyTail=copy;
}
// 链接旧结点
cur->next=next;
// 让旧结点向后遍历
cur=next;
}
// 由于刚开始copyHead就是新链表的头,然后就没有再改变
// 因此copyHead就是新链表的头,直接返回即可
return copyHead;
}