📌  相关文章
📜  用于克隆具有 Next 和随机指针的链表的Java程序集 2(1)

📅  最后修改于: 2023-12-03 14:56:19.478000             🧑  作者: Mango

用于克隆具有 Next 和随机指针的链表的Java程序集 2

本文将介绍如何使用Java编写代码对具有“Next”和“随机”指针的链表进行克隆操作。本文的目标是提供一份易于理解和实现的Java代码示例,并解释其工作原理。代码将涉及“深拷贝”等概念,对于初学者也可以快速上手。

Step 1: 定义一个节点类

首先,我们需要定义一个表示链表节点的类。该类应该包含以下三个属性:

  • val:表示该节点的值。
  • next:表示该节点的下一个节点的指针。
  • random:表示该节点的随机节点的指针。

下面是一个示例的Java类定义:

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

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

在本文的示例代码中,我们假设链表中的节点值为整数型。

Step 2: 分析输入和输出

在本节中,我们将定义输入和输出格式。输入格式将是一个头指针节点,它表示待克隆的链表的头部。输出格式将是克隆后的链表的头部节点。

例如,对于以下链表:

image

输入将是:头指针节点head,表示链表的头节点,head -> [7, null, null]。

输出将是:克隆后的链表的头指针节点cloneNode,表示克隆后的链表的头节点,cloneNode -> [7, null, null]。

Step 3: 克隆链表

现在,我们已经准备好开始编写代码了。我们将遵循以下步骤对链表进行克隆:

  1. 遍历链表,每遇到一个节点就创建一个克隆节点,并将其插入到原节点后面
  2. 再次遍历链表,为每个克隆节点设置random指针
  3. 将链表分成两个独立的部分
  4. 返回克隆后的链表的头部节点

以下是Java代码示例:

public Node cloneLinkedList(Node head) {
    if (head == null) return null;

    // 第一步 - 遍历链表,每遇到一个节点就创建一个克隆节点,并将其插入到原节点后面
    Node curr = head;
    while (curr != null) {
        Node cloneNode = new Node(curr.val);
        cloneNode.next = curr.next;
        curr.next = cloneNode;
        curr = cloneNode.next;
    }

    // 第二步 - 再次遍历链表,为每个克隆节点设置 random 指针
    curr = head;
    while (curr != null) {
        curr.next.random = (curr.random != null) ? curr.random.next : null;
        curr = curr.next.next;
    }

    // 第三步 - 将链表分成两个独立的部分
    curr = head;
    Node cloneHead = head.next;
    while (curr != null) {
        Node cloneNode = curr.next;
        curr.next = cloneNode.next;
        cloneNode.next = (cloneNode.next != null) ? cloneNode.next.next : null;
        curr = curr.next;
    }

    // 第四步 - 返回克隆后的链表的头部节点
    return cloneHead;
}

我们将在以下各节中逐一解释上述代码的每一部分。

第一步 - 插入克隆节点

在这一步中,我们将遍历链表,并在当前节点之后插入一个相同值的克隆节点。这是实现深拷贝的第一步。

Node curr = head;
while (curr != null) {
    Node cloneNode = new Node(curr.val);
    cloneNode.next = curr.next;
    curr.next = cloneNode;
    curr = cloneNode.next;
}

这段代码使用了循环语句。变量curr用来追踪当前操作到的节点。在每次循环中,我们创建一个新的克隆节点cloneNode,并插入到当前节点curr之后。这将导致原先的节点与创建的克隆节点相互连接。然后,我们将curr指向下一个原节点的值。

注意在循环中每个指针节点都会被访问两次,每个节点都会被克隆一次,因此在循环后,链表的长度将翻倍。

第二步 - 设置随机指针

在这一步中,我们将更新每个克隆节点的random指针。这对应于深拷贝的第二步。

curr = head;
while (curr != null) {
    curr.next.random = (curr.random != null) ? curr.random.next : null;
    curr = curr.next.next;
}

变量curr被用来追踪原始链表的节点。在每次循环中,我们将curr指向下一个原始节点的下一个节点(即下一个克隆节点)。这是因为在第一步中,我们将每个克隆节点插入到原始节点之后。因此,我们可以使用下一个克隆节点的随机指针作为当前克隆节点的随机指针。

第三步 - 分离链表

在这一步中,我们将原始链表和克隆链表分离。这对应于深拷贝的第三步。

curr = head;
Node cloneHead = head.next;
while (curr != null) {
    Node cloneNode = curr.next;
    curr.next = cloneNode.next;
    cloneNode.next = (cloneNode.next != null) ? cloneNode.next.next : null;
    curr = curr.next;
}

在本例中,我们假设输入链表的长度为偶数。我们使用变量curr来追踪原始链表的节点。每次循环中,我们将cloneNode指向curr的下一个(即克隆节点)。在这个循环中,我们将克隆节点从原始链表中分离出来,并把curr的原始节点和cloneNode连接起来。两者的下一个节点也必须被连接。这样,原始链表和克隆链表就被分离了。

第四步 - 返回头节点

在这一步中,我们将返回克隆后的链表的头节点

return cloneHead;

这个方法很简单。它只是返回第一步中第一个创建的克隆节点,即cloneHead

Step 4: 总结

在本文中,我们已经编写了一段代码对具有“Next”和“随机”指针的链表进行深拷贝操作。我们遵循了三个步骤,分别是插入克隆节点,设置随机指针和分离链表。这个例子展示了如何使用Java实现深拷贝。如果您有任何问题或需要更多的指导,请随时在下面的评论中留言。我们将在第一时间给您回复。