前言
一个正常的单向单链表我们都会复制,含有随机指向的链表呢?本文介绍如何复制一个含有随机指针的链表。
正文
现在有个一个特殊结构的单链表,他的节点类结构定义如下:
public class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
}
}
其中rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点包括他自己,也有可能指向null。
那么给出一个有Node节点类型组成的单链表的头结点head,如何实现这个链表的复制呢?
思路分析
这道题用Map来辅助实现起来非常简单。
借助集合实现
使用Map来辅助实现思路如下:
- 声明一个
Map,其中Key和Value都是Node类型,Key存放正常节点,Value存在节点对应的rand节点。 - 遍历这个链表
- 将遍历的节点和
rand节点的对应关系存入Map中。
不借助集合实现
在不使用Map的情况下也可以实现这个功能,而且空间复杂度O(1),时间复杂度为O(n)。
假设节点的连接方式为如图所示,按图中的示例分析思路如下:
- 遍历节点,每遍历一个节点生成一个节点的副本插入到节点后
A节点生成一个副本a,a位于A、B中间。B节点生成一个副本b,b位于B、C中间。C节点生成一个副本c,c位于节点之后。
此时调整完后,节点连接方式如下。
之后。
现在还差如何设置节点a、b、c的rand指针,具体方法如下:
- 遍历整个链表,遍历的时候同时取出一对,即
A和a、B和b、C和c。 - 在遍历的时候,可以找到
A的rand指针,把对应的值获取到,并设置到a的rand上。 - 同理,
B和C的处理方式也是一样的。 - 最后一步,分离以及修改整个链表,把
a、b、c对应的链表给拆出来。
代码实现
根据上面的分析,来看下两种方式的代码实现。
借助集合实现
public Node copyRandomList(Node head) {
// key 老节点
// value 新节点
hMap<Node, Node> map = new HashMap<Node, Node>();
Node cur = head;
while (cur != null) {
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
while (cur != null) {
// cur 老
// map.get(cur) 新
// 新.next -> cur.next克隆节点找到
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
不借助集合实现
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
Node cur = head;
Node next = null;
// A -> B -> C -> null
// A -> a -> B -> b -> C -> c
while (cur != null) {
next = cur.next;
cur.next = new Node(cur.val);
cur.next.next = next;
cur = next;
}
cur = head;
Node copy = null;
// A a B b C c
// 依次设置 a b c random指针
while (cur != null) {
next = cur.next.next;
copy = cur.next;
copy.random = cur.random != null ? cur.random.next : null;
cur = next;
}
Node res = head.next;
cur = head;
// 老 新 混在一起,next方向上,random正确
// next方向上,把新老链表分离
while (cur != null) {
next = cur.next.next;
copy = cur.next;
cur.next = next;
copy.next = next != null ? next.next : null;
cur = next;
}
return res;
}
总结
本文介绍如何复制一个含有随机指针的链表,文中通过两种方式对题目的思路进行了分析,并解决了问题。
若有收获就帮忙点个赞吧~