题目:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点(可以为NULL) )。
要求实现一个算法返回一个链表,结构与输入的链表一致(完全的一份拷贝)。
注:
链表结点结构如下:
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {}
};
思路:
这种题目使用的数据结构往往都是在常规数据结构基础之上稍加修改,要求实现一定的功能。
常规的链表解法对本题不太适合,难点在于定位每个结点的random位置。
本文给出的解法时间复杂度为O(n)。
大致思路如下:
对原链表的每个结点生成一个拷贝结点,并链接在其后面。
这样对于长度为n的链表,会生成一个长度为2n的新链表。
另外,对于拷贝结点的特殊指针,此时很容易得到。
newNode->random = oldNode->random->next;
接下来的任务就是将原链表和拷贝链表从整个新链表中分离开。
A、首先获取拷贝链表的头结点 newHead = oldHead->next;
B、定义辅助指针 pNode 和 tmp。
pNode指向当前遍历到的结点 tmp指向pNode的下一个结点 执行:
pNode->next= temp->next; // 拆分源结点和拷贝结点
C、最终返回拷贝链表的头指针即可。
贴代码:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead == NULL)
{
return NULL;
}
RandomListNode* pNode = pHead;
// 对于每个结点 复制一个一模一样的结点
while (pNode)
{
RandomListNode* temp = new RandomListNode(pNode->label);
temp->label = pNode->label;
temp->next = pNode->next;
//temp->random = NULL;
pNode->next = temp;
pNode = temp->next; // 源链表的下一个结点
}
pNode = pHead;
// 指定新分配的每个结点的random(实际上就是源结点的random的next)
while (pNode)
{
RandomListNode* temp = pNode->next;
// 如果源结点的random不指向NULL 为新链表的结点分配random属性
if(pNode->random)
{
temp->random = pNode->random->next;
}
pNode = temp->next;
}
// 分解两个链表
pNode = pHead;
RandomListNode* temp;
RandomListNode *newHead = pHead->next;
while(pNode->next)
{
temp = pNode->next;
pNode->next = temp->next;
pNode = temp;
}
return newHead;
}