【问题标题】:Making a deep copy of a LinkedList in java在java中制作LinkedList的深拷贝
【发布时间】:2014-03-31 00:04:25
【问题描述】:

我有一个链接列表,我正在尝试创建另一个链接列表的副本,这个副本是深层副本,因为元素类型是 char。由于链表的复杂性,我尝试不使用 add 方法。我的代码如下所示。此外,我想递归地将某个列表中的所有元素添加到我的原始列表中,但我的实现的问题是它只添加了列表中的第一个元素,而不是全部。为什么会这样?

public class CharLinkedList {

    private static class Node {
        private char info;
        private Node next;


        public Node(char d) {
            this.data = d;
            this.next = null;
        }
    }

    private int size;
    private Node head;


    public CharLinkedList() {
        this.size = 0;
        this.head = null;
    }


    public CharLinkedList(CharLinkedList some) {
        this.size = some.size;
        Node node = some.head;
        this.head = new Node(other.head.info);
        if(node.next != null)
        {
            this.head.next = new Node(node.next.info);
            node = node.next;
            this.head.next.next = new Node(node.next.info);
        }
    }

    public void addAll(CharLinkedList some) {
        if(some == null){
            return;
        }
        if (this.size == 0) {
            Node someNode = new Node(some.get(0));
            this.head = someNode;
        }
        else {
            CharLinkedList.addAll(some, this.head.next);
        }
        this.size++;
    }

    private static void addAll(CharLinkedList some, Node node) {
        if(node.next == null)
        {
            Node someNode = new Node(some.get(0));
            node.next = someNode;
        }
        else {
            CharLinkedList.addAll(some, node.next);
        }

    }



public static void main(String[] args) {
    CharLinkedList l = new CharLinkedList();
    l.add('z');
    l.add('o');
    l.add('m');

    CharLinkedList some = new CharLinkedList(l);
    some.add('b');
    some.add('i');
    some.add('e');
    System.out.println(l);
    System.out.println(some);
    // now i change the state of l and append all of some
    l.set(1,  'p');
    l.addAll(some);
    System.out.println(l);

【问题讨论】:

  • 为什么不用JCF自带的LinkedList呢?
  • 那么......你有没有让这个工作?如果您能接受答案,那将是您的礼貌。

标签: java recursion deep-copy


【解决方案1】:

这对我来说似乎是一个学术练习(否则我希望您使用 Java Collections Framework 中的 LinkedList<Character>),所以我不会发布完整的方法你。相反,我会尝试引导您为自己创建一个有效的深拷贝实现。

首先 - 我不会使用递归来复制您的列表。如果这样做,您可能会遇到StackOverflowError,因为您的列表越来越大(诚然,对于三元素列表来说这不是问题)。其次,与其让构造函数返回您给它的CharLinkedList 的深层副本,不如重写Object 的clone() 方法(毕竟这就是它的用途)。

如何将每个元素复制到克隆列表中?

好吧,您已经知道您的列表有多大,您将其存储在您的size 属性中。您可以将此值用作for 循环的上限,您可以在其中按顺序复制每个列表元素。

因为您的 CharLinkedList 类仅维护对您的 head 元素的引用,您需要在循环之外维护对 current Node 的引用,否则你会在每次迭代后失去对下一个元素的引用。

本质上,你想要这样的伪代码:

CharLinkedList newList = new CharLinkedList();
Node currentNode = head;

// There are plenty of other ways to do this, you could also use a while loop 
// checking that next is not null.
for (each element up until size) {
    // You may need to implement getData()
    Node newNode = new Node(currentNode.getData()); 
    newList.add(newNode);
    // You may need to implement getNextNode()
    currentNode = currentNode.getNextNode();
}

完成后,return newList,不要忘记记录您的 clone() 方法返回 深度克隆 而不是 浅克隆。为什么? 因为这是一个好习惯。

最后,别忘了看看Java Collections Framework,它已经包含了LinkedList 的实现,您可以阅读其源代码。

【讨论】:

  • 好答案,@JonK。我唯一要修改的是构造函数没有return newList 并且addAll 方法是无效的,所以没有地方可以返回它们。
  • @AlejandroLucena 谢谢你,虽然你的其余评论让我有点困惑(我昨晚睡得很少,所以我可能只是想不通!)。我并不是建议将它添加到构造函数中,恰恰相反,它不应该在构造函数中,它应该是clone() 的覆盖。上面的代码只是伪代码,我故意不想给出一个可行的实现,因为它会破坏学术练习的目的。
  • 我错过了这一点——我错过了你所说的覆盖 clone() 的地方。所以是的,这对clone() 来说是一个很好的替代。我也在下面提出了一个答案,但我没有提到任何关于clone的使用,+1给你
【解决方案2】:

在接受另一个CharLinkedList 的CharLinkedList 构造函数中,您只使用if 语句来检查另一个链表是否有另一个元素,如果有,它将添加为this.head.next .但是,如果有多个元素,则需要将 if 语句转换为 while 并使用临时变量 node 作为各种“迭代器”。

应该这样做:

    Node node = some.head;
    this.head = new Node(some.head.info);
    Node adder = this.head; // keep track of the  adding nodes
    node = node.next; // advance the pointer to the next node
    while(node.next != null) // keep adding to the linked list while there are things to add
    {
        adder.next = new Node(node.info);
        node = node.next; // advance the pointer to the next node
    }

该代码将遍历some 链表并将其每个元素复制到当前正在构建的链表中。

您的addAll 方案中有几个缺陷。添加所有元素的最清晰方法是实现类似于我上面写的解决方案,修改从哪里开始添加等。但是,针对您当前的样式,仅采用 CharLinkedList 的addAll 很好,并且可以使用附加参数正确调用递归addAll,但是在其他addAll 中,您正在检查

   if(node.next == null)

即使您是从前一个函数传递node.next,无论如何它应该是null。此外,您不能确定总是添加第 0 个元素,因为这可能是对链中多个链接的深度递归调用。要继续此实现,您可以添加一个额外的 int 参数来跟踪您在列表中的位置,或者添加一个额外的 Node 参数来指定接下来要添加的内容 - 选择/样式是您的。

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2011-06-27
    • 1970-01-01
    相关资源
    最近更新 更多