在java中制作LinkedList的深层副本

时间:2014-03-31 00:04:26

标签: java recursion deep-copy

我有一个链接列表,我正在尝试创建另一个链接列表的副本,这个副本是一个深层副本,因为元素类型是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);

2 个答案:

答案 0 :(得分:3)

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

首先关闭 - 我不会使用递归来复制您的列表。如果你这样做,你可能会遇到StackOverflowError,因为你的列表变得越来越大(诚然,对于三元素列表来说,这不会是一个问题)。其次,不是让构造函数返回你给它的CharLinkedList的深层副本,而是覆盖Object的{​​{1}}方法(毕竟这就是它的用法)。

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

嗯,您已经知道列表的大小,您将其存储在clone()属性中。您可以将此值用作size循环的上限,您可以在其中按顺序复制每个列表元素。

由于您的for类仅维护对 head 元素的引用,因此您需要在外部维护对当前 CharLinkedList的引用你的循环,否则你会在每次迭代后失去对下一个元素的引用。

从本质上讲,你需要像这样的伪代码:

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方法返回深层克隆而不是浅层克隆< / em>的。为什么? 因为这是一个很好的习惯。

最后,不要忘记查看 Java Collections Framework ,它已经包含了clone()的实现,您可以通过它的源代码阅读。< / p>

答案 1 :(得分:0)

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参数来指定接下来要添加的内容 - 选择/ stye是您的。

希望这有帮助