如何在Java中使用复制构造函数正确复制链表?

How to properly copy a linked list using copy constructor in Java?

提问人:migo101 提问时间:12/4/2021 更新时间:12/4/2021 访问量:972

问:

我无法正确使用复制构造函数来复制 .LinkedList

请看这个例子:

public class LinkedList {
    
    public class Node {
        Node next;
        int val;
        Node(int val) {
            this.val = val;
            next = null;
        }
    }
    public Node head;
    public Node current;
    public LinkedList() {
        
    }
    
    
    public LinkedList(LinkedList another) {
        this.head = another.head;
        this.current = another.current;
    }
    
    public boolean empty() {
        return head == null;
    }
    
    public void insert(int e) {
    
        if (empty()) {
            head = current = new Node(e);
            return;
        }
        Node currNode = new Node(e);
        Node tmp = current;
        tmp.next = currNode;
        current = currNode;
        

    }
    
    public void display() {
        Node currNode = head;
        while (currNode != null) {
            System.out.println(currNode.val);
            currNode = currNode.next;
        }
    }
}

我使用复制构造函数复制了链表,主要代码如下:

public class Main {
    public static void main(String [] args) {
        LinkedList ls = new LinkedList();
        ls.insert(5);
        ls.insert(6);
        ls.insert(7);
        
        LinkedList another = new LinkedList(ls);
        
        another.display();
        another.insert(0);
        ls.display(); // expected output is 5 6 7 
    }
}

代码的输出是,但是我期望它是因为我做了复制,它不会影响。这是怎么回事?如何解决这个问题以获得预期的输出?5 6 7 5 7 6 05 6 7ls

Java Linked-List 复制构造函数

评论

1赞 Mark Lavin 12/4/2021
您的复制构造函数正在执行“某种浅层复制”,因此不会复制实际的节点列表,因此对“另一个”的更改也会影响“ls”。您需要执行“深度复制”,其中复制 ls 中的每个节点。
0赞 Matt Vickery 12/4/2021
嗨,您已经创建了一个新的 LinkedList,但您已将现有 LinkedList 中的 Node 对象引用添加到新 LinkedList 中。这些现有的 Node 对象将在两个 LinkedLists 中增长,因为引用现在是共享的。
0赞 Matt Vickery 12/4/2021
我会考虑添加一个返回对象的克隆方法。从头部开始,要求每个连接的人创建一个自己的克隆副本,链接每个,最后返回头部“节点”的副本。NodeNodeNodeNode
0赞 migo101 12/4/2021
@MarkLavin 你能举个例子吗?

答:

0赞 Mark Lavin 12/4/2021 #1

类似的东西

public LinkedList(const LinkedList& another) {
    this->head = this->current = another.copy()
}

private LinkedList copy( const LinkedList& another ) {
    Node last_node = null;
    Node new_first = null;
    for ( Node next_node = another->head; next_node != null; 
          next_node = next_node->Next ) {
        Node new_node = new Node( next_node );
        if ( new_first == null )
            new_first = new_node;
        if ( last_node != null )
            last_node.Next = new_node
        last_node = next_node;
     }
     return new_first;
}

请注意,我还更改了复制构造函数的签名;通常 该参数应为参考。另外,我的简单解决方案 包含存储泄漏,因为它在从 复制之前不会删除“this”的当前节点。constanother

0赞 Abenamor 12/4/2021 #2

您好,欢迎来到stackoverflow社区

这是您帖子的解决方案:

您可以修改 LinkedList 构造函数,如下所示:

    public LinkedList(LinkedList another) {
        Node previous = another.head;
        Node temp = null;
        // represent a reference to the head of the new linkedList
        Node first = null;
    while (previous != null) {
        Node node = new Node(previous.val);
        if (first == null) {
            first = node;
            temp = first;
        } else {
            temp.next = node;
            temp = temp.next;
        }

        previous = previous.next;
    }

        // set the head
        this.head = first;
        // Temp hold a reference of the last node of the another passed as parameter
        this.current = temp;

}

我在 main 方法中添加了注释,以显示插入前后的链表内容:

        public static void main(String [] args) {
        LinkedList ls = new LinkedList();
        ls.insert(5);
        ls.insert(6);
        ls.insert(7);
        System.out.println("------------ begin display initial list ls");
        ls.display();
        System.out.println("------------ end display initial list ls");

        LinkedList another = new LinkedList(ls);

        System.out.println("------------ begin display another list before insert");
        another.display();
        System.out.println("------------ end display another list before insert");
        System.out.println("------------ Insert 0 in another linked list");

        another.insert(0);

        System.out.println("------------ begin display another list after insert");
        another.display();
        System.out.println("------------ end display another list after insert");
        System.out.println("--------Initial list must not be modified------------");
        ls.display(); // expected output is 5 6 7
        System.out.println("--------end------------");
    }

这是控制台中的结果

 ------------ begin display initial list ls
 5
 6
 7
 ------------ end display initial list ls
 ------------ begin display another list before insert
 5
 6
 7
 ------------ end display another list before insert
 ------------ Insert 0 in another linked list
 ------------ begin display another list after insert
 5
 6
 7
 0
 ------------ end display another list after insert
 --------Initial list must not be modified------------
 5
 6
 7
 --------end------------

我们有预期的结果。