复杂链表的复制:最直观的想法是,如果没有随机指针,那么直接进行尾插法即可,如果寻找链表的中间位置,那么使用快慢指针其中每次快指针走两步慢指针走一步即可,但是随机指针可能指向空,如何判断是尾指针呢?深拷贝后随机指针与原指针不一致,如何实现映射呢?方法来啦!虽然随机指针可能指向空,但是前半部分原链表各个节点均会出现且不为空,线性遍历判断是否为空是不可能的,所以此处使用一个map映射,这样只会将原链表部分映射一次即可,注意,此处的映射是原链表节点和深拷贝节点的映射,因为原链表的链表指针以及随机指针均有。

RandomListNode* Clone(RandomListNode* pHead) 
{
    //创建头结点
    RandomListNode *head=new RandomListNode(-1);
    head->next=nullptr;
    head->random=nullptr;
    //尾结点
    RandomListNode *tail=head;
    //当前结点
    RandomListNode *cur=pHead;
    //原链表结点与深拷贝结点的映射
    unordered_map<RandomListNode *,RandomListNode *> umap;
    //当当前结点不为空并且没有映射 创建原链表结点并且实现next
    while(cur&&umap.find(cur)==umap.end())
    {
        //拷贝结点
        RandomListNode *dcopy=new RandomListNode(cur->label);
        dcopy->next=nullptr;
        //衔接结点
        tail->next=dcopy;
        //映射结点
        umap[cur]=dcopy;
        //移动结点
        tail=tail->next;
        cur=cur->next;
     }
     //根据映射完成原链表节点的random指针
     for(auto [key,value]:umap)
     {
        value->random=key->random==nullptr?nullptr:umap[key->random];
     }
     return head->next;
}

优化:上述方法我们使用了哈希表即使用了辅助空间,那么能不能写出原地实现的方法呢?当然可以!我们首先遍历原链表并创建拷贝链表,将拷贝链表插在对应的原链表之后,得到形如原1-拷1-原2-拷2...的链表,然后通过原链表的随机指针来设置拷贝链表的随机指针,接着将原链表和拷贝链表进行拆分出来,即一个指针指向原链表第一个结点,一个指针指向拷贝链表第一个结点,然后两个指针均每次移动两个位置即可实现。

RandomListNode* Clone(RandomListNode* pHead) 
{
   if(!pHead) return NULL; //空
   //拷贝结点
   RandomListNode *cur=pHead;
   while(cur)
   {
       //创建结点
       RandomListNode *Node=new RandomListNode(cur->label);
       Node->next=NULL;
       //将拷贝结点插在源结点后面
       Node->next=cur->next;
       cur->next=Node;
       //更新当前结点为拷贝结点的下一位
       cur=Node->next;
    }
    //处理拷贝结点的随机指针
    RandomListNode *old=pHead,*newn=pHead->next;
    while(old)
    {
        //将原链表的随机指针赋值给拷贝链表随机指针
        newn->random=old->random==NULL?NULL:old->random->next;
        //原链表走两步
        if(old->next) old=old->next->next;
        //拷贝链表走两步
        if(newn->next) newn=newn->next->next;
    }
    //分离出原链表和拷贝链表
    old=pHead;
    newn=pHead->next;
    //拷贝链表头结点
    RandomListNode *head=newn;
    while(old)
    {
        if(old->next) old->next=old->next->next;
        if(newn->next) newn->next=newn->next->next;
        old=old->next;
        newn=newn->next;
    }
    return head;
}