题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
链表节点的数据结构:
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
在不使用辅助空间的情况下实现O(N)的时间效率。
第一步:根据原始链表的每个结点N创建对应的N’,然后将N’通过next指针接到N的后面。
第二步:设置复制出来的结点的random指针。假设原始链表上的N的random指向结点S,那么其对应复制出来的N’是N->next指向的结点,同样S’也是结点S->next指向的结点,S’=S->next=N->random->next。
第三步:把长链表拆分成两个链表,把奇数位置的结点用pNext连接起来的就是原始链表,把偶数位置的结点通过next连接起来的就是复制链表。这一步中,原有链表也需要从长链表中拆分出来,保持原样。
代码如下:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead == NULL)
{
return NULL;
}
CloneNodes(pHead);
CloneRandom(pHead);
return ReConnectNodes(pHead);
}
void CloneNodes(RandomListNode* pHead)
{
RandomListNode* pCloned = NULL;
while(pHead != NULL)
{
pCloned = new RandomListNode(pHead->label);
pCloned->next = pHead->next;//将新的节点插入到原节点的后面
pHead->next = pCloned;
pHead = pCloned->next;
}
}
void CloneRandom(RandomListNode* pHead)
{
RandomListNode* pCloned;
while(pHead != NULL)
{
pCloned = pHead->next;
if(pHead->random != NULL)
{
pCloned->random = pHead->random->next;
}
pHead = pCloned->next;
}
}
//如上图所示,重构链表的结束条件是pClonedNode->next == NULL
RandomListNode* ReConnectNodes(RandomListNode* pHead)
{
if(pHead == NULL || pHead->next == NULL)
{
return NULL;
}
//返回复制链表的头节点
RandomListNode* pClonedHead = pHead->next;
RandomListNode* pClonedNode = pClonedHead;
RandomListNode* pNode = pHead;
while(pClonedNode->next != NULL)
{
//原来的链表也要恢复
pNode->next = pClonedNode->next;
pNode = pNode->next;
pClonedNode->next = pNode->next;
pClonedNode = pClonedNode->next;
}
return pClonedHead;
}
Lintcode地址:http://lintcode.com/zh-cn/problem/copy-list-with-random-pointer/