第二十四题:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
思路:
这里需要注意一下Java的复制引用和复制(克隆)对象的区别,具体查看https://www.cnblogs.com/kexianting/p/8505056.html
引用和对象
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
if(pHead == null){
return null;
}
//第一步,从到位将所有的结点都复制一遍,复制出来的新节点放在原结点和原结点的next结点之间
//这里得说明一下,currentNode和pHead是两个引用,各自指向内存中的一块内存的地址,
//用pHead给currentNode赋值,是为了让currentNode这个引用指向pHead所指向的那个内存地址
//后面currentNode不断后移,其指向的地址不断的变化,但是pHead指向的地址没有变
RandomListNode currentNode = pHead;
while(currentNode != null){
//clone一份currentNode节点
//这里需要新建一个RandomListNode对象,而不能像上面那种情况直接复制,那样只是创建了同一个对象的一个新的引用
RandomListNode cloneNode = new RandomListNode(currentNode.label);
cloneNode.next = currentNode.next;//将clone出来的新节点的next指针指向currentNode结点的next结点
currentNode.next = cloneNode;//将currentNode结点的next指针指向clone出来的新节点
currentNode = cloneNode.next;//更新currentNode结点
}
//第二步,将所有clone出来的结点的random指向其clone对象结点的random指针指向的结点的next结点
//先将currentNode结点引用指向的地址还原为pHead引用指向的地址
currentNode = pHead;
while(currentNode != null){
//将clone出来的结点的random指向其clone对象结点的random指针指向的结点的next结点
if(currentNode.random == null){
currentNode.next.random = null;
}else{
currentNode.next.random = currentNode.random.next;
}
//更新currentNode引用
currentNode = currentNode.next.next;
}
//第三步,将所有复制的结点所组成的链表和原链表分离开来
//先将currentNode结点引用指向的地址还原为pHead引用指向的地址
currentNode = pHead;
//复制新的头结点的引用
RandomListNode cloneHead = pHead.next;
while(currentNode != null){
RandomListNode cloneNode = currentNode.next;
currentNode.next = cloneNode.next;
//如果cloneNode的next结点是最后一个结点,则新链表的cloneNode的next结点应是next结点,这里注意判断一下这个终止情况
cloneNode.next = cloneNode.next == null ? null : cloneNode.next.next;
currentNode = currentNode.next;
}
return cloneHead;
}
}