面试题26:复杂链表的复制

来源:互联网 发布:淘宝买到三无产品 编辑:程序博客网 时间:2024/06/05 09:54

在面试中,最常见的面试题总绕不过链表,关于链表能考的东西太多,对一个题的思考也能从各个方面展现出现。在《剑指offer》中,复杂链表的复制问题就像是一股清流。

关于链表的复制,大家第一反应都是开辟一个新的空间,然后按照next一直拷贝到结束。如果这个时候,这个链表除了next还含有一个random指针,我们在采用这种复制方法,就得反复去寻找这个自由指针所指向的结点,时间复杂度就会比较高,不能让面试官满意。这个时候,可以考虑一下其他的拷贝方法。

在这里,我能想到的办法是这样的:我们直接在这个链表的每一个结点后面都进行拷贝,然后将这些结点按照现在既有的顺序插入进去。然后在对这个链表进行分离,这样就可以得到新拷贝的链表。过程图如下。

这里写图片描述
这里写图片描述

说完了过程,下来我们具体来实现一下。因为这是一个复杂链表,含有自由指针,所以我们拷贝的时候,先不考虑自由指针怎么拷贝,把链表就当成一个简单的链表进行拷贝。这部分比较简单,就不画图说明,直接上代码。

typedef struct ComplexNode   //链表的结构{    DataType _data; // 数据     struct ComplexNode * _next; // 指向下一个节点的指针     struct ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空) }ComplexNode;
void CloneNode(ComplexNode* head)  //对所有结点进行拷贝{    ComplexNode* cur = head;    while (cur != NULL)    {        ComplexNode* cloneHead = new ComplexNode();  //先将原来的结点除自由指针都进行拷贝        cloneHead->_data = cur->_data;        cloneHead->_next = cur->_next;        cloneHead->_random = NULL;   //不考虑所有的自由指针        cur->_next = cloneHead;        cur = cloneHead->_next;    }}

好了,整个复杂链表的拷贝,我们已经完成了1/3,下来就应该考虑最困难的部分,如何对自由指针进行拷贝。

这里写图片描述

我们现在构建了一个链表如上图,1的自由指针指向了3,2的自由指针指向了4,5的自由指针指向空。经过上面的第一个拷贝后,就会变成下面这样。如下图。

这里写图片描述

这个时候我们就要对自由指针进行拷贝了,我们对原来的链表进行遍历,然后拷贝原有链表的自由指针,接着跳过去我们已经拷贝的新节点。也就是说拷贝1的自由指针后,我们直接去拷贝2的。描述如图。

这里写图片描述

代码如下。

void CloneRandom(ComplexNode* head) //对自由结点进行拷贝{    ComplexNode* cur = head;    while (cur != NULL)    {        ComplexNode* cloneHead = cur->_next;        if (cur->_random  != NULL)        {            cloneHead->_random = cur->_random->_next;        }        cur = cloneHead->_next;    }}

最后一步,把两个链表分离出来。这部分比较简单,但是需要注意的是,我们一定要先找出两个链表各自的头。然后分别让它们指向属于自己的部分。

ComplexNode* ConnectList(ComplexNode* head){    ComplexNode* cur = head;    ComplexNode* newHead = NULL;    ComplexNode* cloneNext = NULL;    if (cur != NULL)   //先找出各自的头    {        newHead = cloneNext = cur->_next;        cur->_next = cloneNext->_next;        cur = cur->_next;    }    while (cur != NULL)  //再将各自的结点分别链起来    {        cloneNext->_next = cur->_next;        cloneNext = cloneNext->_next;        cur->_next = cloneNext->_next;        cur = cur->_next;    }    return newHead;}

总结:遇到一个复杂的问题时,可以考虑各个击破,把一个复杂问题一步一步变简单。