复制带随机指针的链表 + 画图分析
题目要求
1.控制随机指针:新的链表节点的random指针指向和原链表相对应新链表的数据。
举个例子:原链表的中间节点的random如果指向原链表的头节点,则新链表的中间节点的random指向新链表的头节点。
2.原链表保持不变
3.原链表和复制链表中的这些指针能够表示相同的链表指向。
解题思路 + 画图分析 + 解题步骤
目标:使用原节点快速找到拷贝节点。 如果实现目标,上面的一切要求都迎刃而解。
解题思路三步走:
第一步
每个原节点,在其后一个位置都拷贝一个,并链接在一起。如下图所示。
第二步
寻找新节点的random,而新节点的random就是原来random->next。如下图所示
第三步
把拷贝的节点取出,链接成新的链表,同时恢复原链表。如下图所示:
题解
对应第一步的代码:拷贝节点
//首先设立三个指针,分别指向对应图上的位置,前中后
struct Node* cur = head;
while (cur)
{
struct Node* next = cur->next;
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
if(NULL == copy)
{
perror("malloc");
return NULL;
}
//把原节点的数据赋值给拷贝节点的数据域
copy->val = cur->val;
//更新指针
cur->next = copy;
copy->next = next;
cur = next;
}
对应第二步的代码:寻找拷贝节点random的位置
//重置cur
cur = head;
while (cur)
{
//两个指针cur指向原节点,copy指向该原节点的拷贝节点
struct Node* copy = cur->next;
//对random指向空进行特殊处理
if (NULL == cur->random)
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
//更新指针
cur = cur->next->next;
}
对应第三步的代码:拆取拷贝节点,链成新的链表,恢复原链表
//拆取
//重置cur
cur = head;
//定义拷贝链表的头节点和尾节点
struct Node* copyHead = NULL;
struct Node* tail = NULL;
while (cur)
{
//如第一步定义三个指针,前中后
struct Node* copy = cur->next;
struct Node* next = copy->next;
//首先解决头节点为空的情况
if (copyHead == NULL)
{
copyHead = tail = copy;
}
else
{
//尾插
tail->next = copy;
tail = tail->next;
}
//恢复
cur->next = next;
//更新指针
cur = next;
}//End of while
全部代码步骤合在一起
struct Node* copyRandomList(struct Node* head)
{
struct Node* cur = head;
while (cur)
{
struct Node* next = cur->next;
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
if(NULL == copy)
{
perror("malloc");
return NULL;
}
copy->val = cur->val;
cur->next = copy;
copy->next = next;
cur = next;
}
cur = head;
while (cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
if (NULL == cur->random)
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
cur = next;
}
//拆
cur = head;
struct Node* copyHead = NULL;
struct Node* tail = NULL;
while (cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
if (copyHead == NULL)
{
copyHead = tail = copy;
}
else
{
tail->next = copy;
tail = tail->next;
}
//恢复
cur->next = next;
cur = next;
}
return copyHead;
}
总结
复杂链表的复制这一题,为中等难度。做出这一题代表对单链表有一定理解。
当借鉴的多了,思考的多了,也会形成属于自己的思想。