实现链表代码的问题

时间:2012-09-12 04:47:07

标签: java list concatenation pass-by-reference

在我的链表实现中,有两种方法。当我调用一个方法时,它会影响另一个方法的结果。一种方法是concatenateLL()来连接两个列表,一种方法是getNumberOfNodes(),它返回链表中的节点数。对于我的方法连接,我应该返回一个新列表,它是两个列表的串联。但是在我的代码中,生成的新列表会影响第一个参数中的列表。让我说我传递列表lm和参数,然后我返回一个新列表。

问题是新的只是列表l,它现在包含列表m的元素(由于连接)。因此,当我在列表getNumberOfNodes()l上调用m时,我得到了错误的值。

这是我的代码:

public static LinkedList concatenateLL(LinkedList l, LinkedList m) {
    LinkedList a = l;
    Node l_last = a.getTailNode();
    Node m_first = m.getHeadNode();
    l_last.setNext(m_first);
    a.tail = m.getTailNode();
    return a;
}

public int getNumberOfNodes(Node h) {
    if(h == null)
        return 0;
    return 1 + getNumberOfNodes(h.getNext());
}

public static void print(LinkedList l) {
    Node v = l.getHeadNode();
    while(v != null) {
        System.out.print(v.getElement()+" ");
        v = v.getNext();
    }
    System.out.println();
}

public static void main(String[] args) throws IndexOutOfBoundsException {
    // TODO Auto-generated method stub
    LinkedList l = new LinkedList();
    LinkedList m = new LinkedList();
    l.insertFirst(5);
    l.insertFirst(7);
    l.insertFirst(3);
    l.insertFirst(6);
    print(l);
    m.insertFirst(2);
    m.insertFirst(4);
    m.insertFirst(9);
    m.insertFirst(8);
    m.insertLast(10);
    m.insertLast(12);
    print(m);
    LinkedList n = concatenateLL(l, m);
    print(n);
    System.out.println(l.getNumberOfNodes(l.getHeadNode()));
    System.out.println(m.getNumberOfNodes(m.getHeadNode()));
}

在主要方法中,列表l的长度应返回4,列表m应返回6。但是在我调用getNumberOfNodes()之前调用连接方法之后,我得l的长度为10(这是n的节点数,因为{{{}}连接的结果1}}和l)以及m的长度为m(我不明白为什么)。

3 个答案:

答案 0 :(得分:1)

当我看到你的代码时,我猜你习惯用C / C ++编写(基于命名约定和预期行为)。您的问题在于进行深层复制。在concatenateLL方法的开头,您需要对两个列表进行深层复制,然后您可以按照当前的方式将它们连接起来。

LinkedList a = l; // problem line

在C / C ++中,它会调用一个复制构造函数,但是Java没有这样的东西,所以你需要自己实现它。您可以使用clone()声明的方法java.lang.Object并覆盖它,但您需要使深层复制不浅,因为您还要更改节点之间的引用,而不仅仅是列表

例如,该方法可能看起来像这样:

public static LinkedList concatenateLL(LinkedList l, LinkedList m) {
   LinkedList a = new LinkedList();

   // copy Nodes, you need to create new instance of them
   for ( int i = 0; i < l.getNumberOfNodes(l.getHeadNode()); ++i )
        a.insertLast( l.getNode( i ) );

   // copy Nodes, you need to create new instance of them
   for ( int i = 0; i < m.getNumberOfNodes(m.getHeadNode()); ++i )
        a.insertLast( m.getNode( i ) );

   return a;
}

但我需要提一下,由于方法O(n^2)getNode(),此实施的复杂度为O(n)。更好的解决方案是使用迭代器,但我不知道你的类是否实现它。

修改 为了提高O(n)的复杂性,我建议你实现标准接口Iterator无论如何,重点在于保持对当前元素的引用能够简单地获得下一个。如果我举一个简单的例子:

Node item = l.getHeadNode();

while( item != null ) {
    // copy the item
    a.insertLast( item );
    item = item.getNext();
}

列表m也一样。

答案 1 :(得分:0)

是的,LInkedList a = l;不会创建链接列表l的副本。

如果您不想修改l,则必须创建新的链接列表。

答案 2 :(得分:0)

public static LinkedList concatenateLL(LinkedList l, LinkedList m) {
    LinkedList a = new LinkedList();
    Node l_last = l.getHeadNode();
    Node m_first = m.getHeadNode();
    while(l_last != null) {
        a.insertLast(l_last.getElement());
        l_last = l_last.getNext();
    }
    while(m_first != null) {
        a.insertLast(m_first.getElement());
        m_first = m_first.getNext();
    }       
     return a;
}