1,题目:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。求一个复制体。
2,考虑点:
(1),链表为空的情况。
(2),链表只有一个结点的情况以及在遍历链表的过程中考虑当前只有一个结点的情况
3,方法:
(1),先复制单链表,再考虑特殊指针:每找一次特殊指针,从头遍历原链表一次(因为特殊指针有可能指向当前节点的前面节点),通过比较顺序指针和特殊指针是否相等(为什么不比较值呢?因为链表中没说值不可以重复),记录顺序指针走的步数,同理在赋值链表中,走这么多步,找到谁,就把谁赋值给当前节点的特殊指针。
时间复杂度为O(n2)。
(2),用map容器key-value思想,对每一个原链表的节点p,在复制后有p',使(p,p')形成键值对;这样在复制得到单链表后,就得到了一个map,然后扫描map每一个键值对(p,p'),找到p->random 键值对用(q,q')表示,那么p'->random就等于q‘。
(3),从头遍历链表,对每一个节点复制一个,插在它后边;接着遍历这个链表,那么原链表中节点的特殊指针若为空,则复制链表对应节点的特殊指针也为空,若源链表中结点的特殊指针不为空,那复制链表中对应节点的特殊指针为原链表中结点特殊指针的->next。
接着就是拆分了。
这是在牛客网上用第三种方法实现的代码:
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if (!pHead)
{
return NULL;
}
RandomListNode* pNode = pHead;
RandomListNode* nextNode = pNode->next;
while (pNode)
{
RandomListNode *temp = new RandomListNode(pNode->label);
pNode->next = temp;
temp->next = nextNode;
pNode = temp->next;//新的起点
if (pNode)
{
nextNode = pNode->next;//这里是判断链表本身只有一个结点时和遍历到最后时两种情况
}
}//每个节点复制一次,连接起来,间隔构成两个单链表
//下边是要扫描链表,求random指针
pNode = pHead;
while (pNode)
{
if (!pNode->random)
{
pNode->next->random = NULL;
}
else
pNode->next->random = pNode->random->next;
pNode = pNode->next->next;
}
//下边就是要拆开了
RandomListNode* ClonepHead = pHead->next;
RandomListNode* ClonepNode = ClonepHead;
pNode = pHead;
while (pNode)
{
pNode->next = ClonepNode->next;
pNode = pNode->next;
if (pNode)//遍历过程中需要判断链表本身只有一个结点时和遍历到最后时两种情况
{
ClonepNode->next = pNode->next;
ClonepNode = ClonepNode->next;
}
}
return ClonepHead;
}
};
第二种方法的实现代码:
用到stl中的map容器,各种出错啊,没用过,很不熟练,出了很多问题!
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
//用key-value的思想
if (!pHead)
{
return NULL;
}
//先复制单链表并建立好<a, a'>a是原链表结点地址,a'是复制的对应结点地址
//map(RandomListNode*, RandomListNode*) mymap;//这里可以用map容器,因为地址满足<关系
//容器是个尖括号,操!
map<RandomListNode*, RandomListNode*> mymap;
RandomListNode* pNode = pHead;
RandomListNode* ColomnpNode = NULL;
RandomListNode* ColomnpHead = NULL;//用来保存复制链表的头指针
if (pNode)//先复制第一个结点
{
ColomnpNode = new RandomListNode(pNode->label);
ColomnpHead = ColomnpNode;
mymap[pNode] = ColomnpNode;//往map中插入地址对
pNode = pNode->next;
//ColomnpNode = ColomnpNode->next;//这里出错了,链表断开了
//这个赋值语句只是把ColomnpNode变成NULL,没起来连接的作用
}
while (pNode)
{
RandomListNode* temp = new RandomListNode(pNode->label);
//紧接上个注释,对它的修改为
ColomnpNode->next = temp;//起到连接的作用了,得先申请空间,再用next连接
ColomnpNode = temp;
mymap[pNode] = ColomnpNode;
pNode = pNode->next;
//ColomnpNode = ColomnpNode->next;
}
//根据mymap来求random指针
pNode = pHead;
// mymap<RandomListNode*, RandomListNode*>::iterator it;
// mymap<RandomListNode*, RandomListNode*>::iterator it1;//声明迭代器不是用mymap
map<RandomListNode*, RandomListNode*>::iterator it;
map<RandomListNode*, RandomListNode*>::iterator it1;
while (pNode)
{
if (pNode->random != NULL)
{
it = mymap.find(pNode);
if (it != mymap.end())
{
it1 = mymap.find(pNode->random);//这里最好不要用it->first->random;
if (it1 != mymap.end()) //涉及到迭代器还是谨慎为妙!
{
it->second->random = it1->second;
}
}
}
pNode = pNode->next;
}
return ColomnpHead;
}
};
得多用用map!