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

来源:互联网 发布:nginx 限制ip访问次数 编辑:程序博客网 时间:2024/05/23 00:27

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

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




原创粉丝点击