剑指offer面试题26-复杂链表的复制

题目:给定一个复杂链表,对其进行复制产生一个新的复杂链表。复杂链表中每个节点中有三个部分:数据域,指向链表中下一个节点的指针,指向链表中其他任意一个节点的指针。复杂链表中节点的定义如下:

struct complexLinkNode
{
     int data;//数据域
     struct complexLinkNode *next;//指向下一个节点的指针
     struct complexLinkNode *ptr;//指向链表中其他任意一个节点的指针
}

这个题第一眼看到时不算太难,但是如果想要实现高效的拷贝(时间复杂度为O(n)),有一定难度。在这里对这个问题进行一下分析。以下面一个复杂链表为例进行分析

剑指offer面试题26-复杂链表的复制_第1张图片

方法一:使用一个hash表进行存储的方式,以达到O(n)的效果。

1.过程描述:

第一遍首先扫原始的描复杂链表,并进行拷贝生成新的链表,链表中每个节点的ptr域先置为NULL。锁使用的时间复杂度为n。

在扫描的过程中使用一个hash表将原始复杂链表中的每个点内存与生成的表的内存建立一个映射,接下来用这个hash表来建立每个节点的指向关系。

剑指offer面试题26-复杂链表的复制_第2张图片

第二轮同时扫描两个复杂链表,找到原始复杂链表中每一个节点的ptr值,然后使用hash表求得对应的ptr值在新生成的复杂链表中的值,然后使新生成的节点中的ptr值指向它就行了。

下面用一个例子说明下:

(1)原始复杂链表中第一个点4ptr值为NULL,所以新生成的复杂链表的ptr也为NULL。

(2)原始复杂链表中第二个点6ptr指向第三个点。则新的复杂链表中,第二个点中ptr值,指向原始复杂链表中第二个点的ptr值对应的hash值。

即为:新的复杂链表第二个点的ptr = hash(原始复杂链表中第二个点的ptr值);

对于其他的点依次往后即可。

剑指offer面试题26-复杂链表的复制_第3张图片

2.实现代码:

#include
#include
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;
	mapm;
	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。经过这一轮后

剑指offer面试题26-复杂链表的复制_第4张图片

第二步:修改新产生节点的ptr指针。在原始链表中6的ptr指向节点2,那么新产生的节点6(红色的)的ptr应该是节点2的next。由此我们就可以得到所有新产生节点ptr。

剑指offer面试题26-复杂链表的复制_第5张图片

第三步:将第二步产生的链表分开,奇数位置的构成一个单独链表,偶数位置的构成一个单独链表。

剑指offer面试题26-复杂链表的复制_第6张图片

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表来实现。




你可能感兴趣的:(剑指offer面试题26-复杂链表的复制)