题目:给定一个复杂链表,对其进行复制产生一个新的复杂链表。复杂链表中每个节点中有三个部分:数据域,指向链表中下一个节点的指针,指向链表中其他任意一个节点的指针。复杂链表中节点的定义如下:
struct complexLinkNode
{
int data;//数据域
struct complexLinkNode *next;//指向下一个节点的指针
struct complexLinkNode *ptr;//指向链表中其他任意一个节点的指针
}
这个题第一眼看到时不算太难,但是如果想要实现高效的拷贝(时间复杂度为O(n)),有一定难度。在这里对这个问题进行一下分析。以下面一个复杂链表为例进行分析
方法一:使用一个hash表进行存储的方式,以达到O(n)的效果。
1.过程描述:
第一遍首先扫原始的描复杂链表,并进行拷贝生成新的链表,链表中每个节点的ptr域先置为NULL。锁使用的时间复杂度为n。
在扫描的过程中使用一个hash表将原始复杂链表中的每个点内存与生成的表的内存建立一个映射,接下来用这个hash表来建立每个节点的指向关系。
第二轮同时扫描两个复杂链表,找到原始复杂链表中每一个节点的ptr值,然后使用hash表求得对应的ptr值在新生成的复杂链表中的值,然后使新生成的节点中的ptr值指向它就行了。
下面用一个例子说明下:
(1)原始复杂链表中第一个点4ptr值为NULL,所以新生成的复杂链表的ptr也为NULL。
(2)原始复杂链表中第二个点6ptr指向第三个点。则新的复杂链表中,第二个点中ptr值,指向原始复杂链表中第二个点的ptr值对应的hash值。
即为:新的复杂链表第二个点的ptr = hash(原始复杂链表中第二个点的ptr值);
对于其他的点依次往后即可。
2.实现代码:
#include<iostream>
#include<map>
using namespace std;
struct complexLinkNode
{
int data;
struct complexLinkNode * next;
struct complexLinkNode *ptr;
};
complexLinkNode *copy(complexLinkNode *head)
{
if (head == NULL)
return NULL;
complexLinkNode *newHead = NULL;
complexLinkNode *p = head;
complexLinkNode *q = NULL;
map<complexLinkNode *, complexLinkNode *>m;
while (p != NULL)//第一次扫描
{
if (newHead == NULL)
{
newHead = (complexLinkNode *)malloc(sizeof(complexLinkNode));
newHead->data = p->data;
newHead->next = newHead->ptr = NULL;
q = newHead;
}
else
{
complexLinkNode *qq = (complexLinkNode *)malloc(sizeof(complexLinkNode));
qq->data = p->data;
qq->next = qq->ptr = NULL;
q->next = qq;
q = qq;
}
m.insert(make_pair(p, q));//将原始复杂链表中的点与新复杂链表中的点建立一个对应的hash关系
p = p->next;
}
p = head;
q = newHead;
while (p != NULL && q != NULL)//第二遍扫描原始复杂链表,使用hash表建立每个节点中的ptr关系
{
if (p->ptr != NULL)
{
q->ptr = m[p->ptr];
}
p = p->next;
q = q->next;
}
return newHead;
}
这样的一个方法,虽说能够在O(n)时间实现复杂链表拷贝,但是增加了一个额外的开销就是使用了hash表。接下来,将会介绍一个不用增加额外开销就可以个实现复制功能。
方法二:具体看过程
1、过程描述
第一轮首先根据原始链表中的每一个节点拷贝出一个新的节点。每个新节点作为产生该新节点的原始节点后继,新节点的ptr先置为NULL。经过这一轮后
第二步:修改新产生节点的ptr指针。在原始链表中6的ptr指向节点2,那么新产生的节点6(红色的)的ptr应该是节点2的next。由此我们就可以得到所有新产生节点ptr。
第三步:将第二步产生的链表分开,奇数位置的构成一个单独链表,偶数位置的构成一个单独链表。
2、实现代码
void stepOne(complexLinkNode *&head)
{
if (head == NULL)
return;
complexLinkNode *p = head;
while (p != NULL)
{
complexLinkNode *temp = (complexLinkNode *)malloc(sizeof(complexLinkNode));
temp->data = p->data;
temp->next = p->next;
temp->ptr = NULL;
p->next = temp;
p = temp->next;
}
}
void stepTwo(complexLinkNode *&head)//修改新生成的节点的ptr域,head这个链表中节点个数一定是偶数个
{
if (head == NULL)
return;
complexLinkNode *p = head;
while (p != NULL)
{
if (p->ptr != NULL)
{
p->next->ptr = p->ptr->next;
}
p = p->next->next;
}
}
complexLinkNode* stepThree(complexLinkNode *&head)
{
if (head == NULL)
return;
complexLinkNode *newHead = NULL;
complexLinkNode *p = head;
newHead = p->next;
complexLinkNode *q = newHead;
while (p != NULL)
{
p->next = q->next;
p = p->next;
if (p != NULL)
{
q->next = p->next;
q = q->next;
}
}
return newHead;
}
这个过程不用借助于额外的hash表来实现。