/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/

复制链表并拆分
思路: 直接在原链表基础上复制新链表,即让原节点next指向自己的拷贝节点,然后拆分random, 
拷贝节点的random指向其指向的原节点的next,最后,再拆next,让其每一个节点next都指向其原来指向的下一节点,
文字描述有点晦涩,直接上图(图中合并部分,即拷贝过程中,由于空间有限,没有画出原有链表的random指向,
其实原有链表的指向和拷贝之前的一样)
Step1:复制原链表中每一个节点,使得拷贝后的新节点在原节点的下一个节点;
Step2:拷贝后的新节点的random指向节点与原链表节点的random指向节点一致;
Step3:拆分链表,原节点依次连接,拷贝后的新节点依次连接。


* 哈希表
使用哈希表map表示映射关系,其中哈希表的键值key是原节点,value值是复制的新节点。
步骤:
第一步是遍历原链表,利用哈希表映射新节点和旧节点关系,即每遍历一个节点,则复制一个val值相同的新节点,
mp[p]= new Node(p->val)。
第二步是遍历map,复制next和random指针的对应关系,并更新新节点的next和random所指的值,
最后返回新链表的头节点即可,即即mp[p]->next=mp[p->next]和mp[p]->random=mp[p->random]。
class Solution {
public:
    /*
    复制链表并拆分
    思路: 直接在原链表基础上复制新链表,即让原节点next指向自己的拷贝节点,然后拆分random, 
    拷贝节点的random指向其指向的原节点的next,最后,再拆next,让其每一个节点next都指向其原来指向的下一节点,
    文字描述有点晦涩,直接上图(图中合并部分,即拷贝过程中,由于空间有限,没有画出原有链表的random指向,
    其实原有链表的指向和拷贝之前的一样)
    Step1:复制原链表中每一个节点,使得拷贝后的新节点在原节点的下一个节点;
    Step2:拷贝后的新节点的random指向节点与原链表节点的random指向节点一致;
    Step3:拆分链表,原节点依次连接,拷贝后的新节点依次连接。
    */
    /*
    RandomListNode* Clone(RandomListNode* pHead) {
        if(pHead == nullptr) {
            return nullptr;
        }

        //Step1:复制原链表中每一个节点,使得拷贝后的新节点在原节点的下一个节点;
        RandomListNode *pHeadNode = pHead;
        while(pHeadNode != nullptr) {
            RandomListNode *pNewNode = new RandomListNode(pHeadNode->label); //创建头结点
            RandomListNode *pNextNode = pHeadNode->next; //下一个节点
            pHeadNode->next = pNewNode; //尾插法:头结点连接新节点
            pNewNode->next = pNextNode; //新节点连接下一个节点
            pHeadNode = pNewNode->next; //向后移位
        }
        // Step2:拷贝后的新节点的random指向节点与原链表节点的random指向节点一致;
        pHeadNode = pHead;
        while(pHeadNode != nullptr) {
            if (pHeadNode->random != nullptr) {
                pHeadNode->next->random = pHeadNode->random->next;
            }
            pHeadNode = pHeadNode->next->next;
        }
        // Step3:拆分链表,原节点依次连接,拷贝后的新节点依次连接。
        pHeadNode = pHead;
        RandomListNode *pFirstNode = pHead->next;
        RandomListNode *pSecondNode = pHead->next;
        while(pHeadNode != nullptr) {
            pHeadNode->next = pHeadNode->next->next; //第一个节点连接第三节点,断开第二个节点
            pHeadNode = pHeadNode->next; //向后移位
            if(pFirstNode->next != nullptr) {
                pFirstNode->next = pFirstNode->next->next;
                pFirstNode = pFirstNode->next;
            }
        }
        return pSecondNode;
    }
    */

    /*
    * 哈希表
    使用哈希表map表示映射关系,其中哈希表的键值key是原节点,value值是复制的新节点。
    步骤:
    第一步是遍历原链表,利用哈希表映射新节点和旧节点关系,即每遍历一个节点,则复制一个val值相同的新节点,
    mp[p]= new Node(p->val)。
    第二步是遍历map,复制next和random指针的对应关系,并更新新节点的next和random所指的值,
    最后返回新链表的头节点即可,即即mp[p]->next=mp[p->next]和mp[p]->random=mp[p->random]。
    */
    RandomListNode* Clone(RandomListNode* pHead) {
        if(pHead == nullptr) {
            return nullptr;
        }

        unordered_map<RandomListNode*, RandomListNode*> mpNode;
        RandomListNode* pHeadNode = pHead;
        while(pHeadNode != nullptr) {
            mpNode[pHeadNode] = new RandomListNode(pHeadNode->label);
            pHeadNode = pHeadNode->next;
        }

        pHeadNode = pHead;
        while(pHeadNode != nullptr) {
            if(pHeadNode->next != nullptr) {
                mpNode[pHeadNode]->next = mpNode[pHeadNode->next]; // 拷贝节点连接下一个节点
            }
            if(pHeadNode->random != nullptr) {
                mpNode[pHeadNode]->random = mpNode[pHeadNode->random];
            }
            pHeadNode = pHeadNode->next;
        }

        return mpNode[pHead];
    }
};