1、题目描述
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深拷贝
2、分析
这里需要注意,要返回的链表是旧链表的深拷贝,所以新链表的数据域必须是一样的。再来看next域和随机指针域呢?也一样吗?
当然是不可以,next域和random存放的都是地址,物理地址是唯一标识,如果地址一样那后果就不可设想了。也就是说新的链表种要满足的就是以下条件:
- 数据域一模一样
- 新链表的每个节点next域保留的下一个节点对应一样的的,比如原链表种2节点后面是4
新的链表中,2后面对应的仍然要是4,需要保持一个这样的对应关系
- 对于随机指针域的要求也和next域的要求一样,必须对应。
3、具体做法:
- 将复制链表的节点一个个插入到原链表中,使得旧链表和复制链表串为一个链表。具体:
A:定义新的节点node ,把random域暂时置为null
Node node = new Node(cur.val,cur.next,null)
//需要下这注意这一句,这里复制后的新链表的每一个节点的next域都已经保存了下一个节点的地址值,也就是新节点的next域已经串好了。
B: 定义cur遍历旧链表,定义temp指向旧链表 cur的下一个节点,将复制的节点插入到旧链表中。由A步骤我们知道复制链表的next域已经连起来了,这里只需要搞定原链表的next域即可。
Node cur = this.head;
Node temp = cur.next;
//把复制的节点串上去
cur.next = node;
//更新一下当前的cur
cur = temp;
将所有的节点串好后
C:借助这个合成的链表处理random域,再次把cur拉到头前,遍历合成的这个链表的旧的部分(就是保证cur每次走两步)
if(random != null){
cur.next.random = cur.random.next;
}
也就是这里我们借助了原链表,当这个旧链表的随机指针有指向别的节点的时候,在这个合成链表中,旧链表的random域指向的节点,和新链表random逻辑上需要对应,简单讲,你会从图中发现,如果当前cur的random域不为null,那这个节点的下一个节点,也就是我们要复制的这个节点也不为null,并且这个节点的random域所指向节点,其下一个节点就是复制节点random应该指向的值,借用这个规则可以处理好所有的random。
D:拆分出复制后的链表
cur = head;
Node newHead = cur.next;
while(cur.next != null){
Node temp = cur.next;
cur.next = temp.next;
cur = temp;
}
java描述的源代码
public Node copyRandomList(Node head) {
if(head == null){
return null;
}
Node cur = head;
while(cur != null){
Node node = new Node(cur.val,cur.next,null);
Node temp = cur.next;
cur.next = node;
cur = temp;
}
cur = head;
while(cur != null){
if(cur.random != null){
cur.next.random = cur.random.next;
} else {
cur.next.random = null;
}
cur = cur.next.next;
}
cur = head;
Node newHead = cur.next;
while(cur.next != null){
Node temp = cur.next;
cur.next = temp.next;
cur = temp;
}
return newHead;
}