如何复制一个含有随机指针的链表?

161 阅读3分钟

前言

一个正常的单向单链表我们都会复制,含有随机指向的链表呢?本文介绍如何复制一个含有随机指针的链表。

正文

现在有个一个特殊结构的单链表,他的节点类结构定义如下:

public class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
    }
}

其中rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点包括他自己,也有可能指向null

那么给出一个有Node节点类型组成的单链表的头结点head,如何实现这个链表的复制呢?

思路分析

这道题用Map来辅助实现起来非常简单。

借助集合实现

使用Map来辅助实现思路如下:

  • 声明一个Map,其中KeyValue都是Node类型,Key存放正常节点,Value存在节点对应的rand节点。
  • 遍历这个链表
  • 将遍历的节点和rand节点的对应关系存入Map中。

不借助集合实现

在不使用Map的情况下也可以实现这个功能,而且空间复杂度O(1),时间复杂度为O(n)

假设节点的连接方式为如图所示,按图中的示例分析思路如下:

  • 遍历节点,每遍历一个节点生成一个节点的副本插入到节点后
  • A节点生成一个副本aa位于AB中间。
  • B节点生成一个副本bb位于BC中间。
  • C节点生成一个副本cc位于节点之后。

此时调整完后,节点连接方式如下。

之后。

现在还差如何设置节点abcrand指针,具体方法如下:

  • 遍历整个链表,遍历的时候同时取出一对,即AaBbCc
  • 在遍历的时候,可以找到Arand指针,把对应的值获取到,并设置到arand上。
  • 同理,BC的处理方式也是一样的。
  • 最后一步,分离以及修改整个链表,把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;
}

总结

本文介绍如何复制一个含有随机指针的链表,文中通过两种方式对题目的思路进行了分析,并解决了问题。

若有收获就帮忙点个赞吧~