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

在面试中,最常见的面试题总绕不过链表,关于链表能考的东西太多,对一个题的思考也能从各个方面展现出现。在《剑指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;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值