【问题标题】:why is my customized LinkedList not working?为什么我的自定义 LinkedList 不起作用?
【发布时间】:2017-02-06 05:12:17
【问题描述】:

我正在尝试创建自定义的 LinkedList 以更好地理解数据结构。我无法弄清楚我的 LinkedList 类的问题是什么。

package numberlist.primitivelist.objectlist;

public class ObjectLinkedList extends ObjectList implements Copiable {

Node firstNode;

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: ObjectLinkedList() description:constructor
 *
 * @author Jinyu Wu Date: 2017/2/4
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
public ObjectLinkedList() {
    firstNode = null;
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: add() description: Insert an item into the list
 *
 * @param index position of the list
 * @param obj the element is going to be inserted
 * @author Jinyu Wu Date: 2017/2/4
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public void add(int index, Object obj) {
    Node tempNode = firstNode;
    Node currentNode = new Node(obj);
    if (index == 0) {
        firstNode = currentNode;
        return;
    }
    if (index < 0 || index > size()) {
        System.out.println("add(ObjectLinkedList) index out of bound exception");
    } else {
        for (int i = 1; i <= index; i++) {
            tempNode = tempNode.getNext();
            if (i == index - 1) {
                if (index != size() - 1) {
                    currentNode.setNext(tempNode.getNext());
                } else {
                    currentNode.setNext(null);
                }
                tempNode.setNext(currentNode);
            }
        }
    }

}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: removeAt() description: remove an item from a position of the
 * list
 *
 * @param index position in the list
 * @author Jinyu Wu Date: 2017/2/4
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public void removeAt(int index) {
    if (index < 0 || index > size()) {
        System.out.println("removeAt(ObjectLinkedList) index out of bound exception");
    } else {
        Node tempNode = firstNode;
        if (index == 0) {
            firstNode = firstNode.getNext();
        } else {
            for (int i = 1; i <= index; i++) {
                tempNode = tempNode.getNext();
                if (i == index - 1) {
                    if (index != size() - 1) {
                        tempNode.setNext(tempNode.getNext().getNext());
                    } else {
                        tempNode.setNext(null);
                    }
                }
            }
        }
    }

}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: remove() description: remove a specific item from a position of
 * the list
 *
 * @param obj target object is going to be removed
 * @author Jinyu Wu Date: 2017/2/4
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public void remove(Object obj) {
    if (size() > 0) {
        Node tempNode = firstNode;
        for (int i = 0; i <= size(); i++) {
            if (tempNode.equals(obj)) {
                tempNode.setNext(tempNode.getNext().getNext());
                break;
            }
            if (i < size() - 1) {
                tempNode = tempNode.getNext();
            }
        }

        System.out.println("target object is not found inside the linkedList(remove)");
    }
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: get() description:get an item from the list
 *
 * @param index position in the list
 * @author Jinyu Wu Date: 2017/2/4
 * @return double ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public Object get(int index) {
    if (index < 0 || index > size()) {
        System.out.println("get(ObjectLinkedList) index out of bound exception");
        return null;
    } else if (index == 0) {
        return firstNode;
    } else {
        Node tempNode = firstNode;
        for (int i = 0; i <= index; i++) {
            if (i == index - 1) {
                tempNode = tempNode.getNext();
                return tempNode;
            }
        }
        System.out.println("objectLinkedList get method nothing found");
        return null;
    }

}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: toString() description: print out the content of the list
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @return Integer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public String toString() {
    return "ObjectLinkedList{" + "firstNode=" + firstNode + '}';
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: find() description:get an item from the list
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @param obj Object is going to be found
 * @return Integer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public int find(Object obj) {
    Node tempNode = firstNode;
    Node newNode = new Node(obj);
    if (newNode.equals(firstNode)) {
        return 0;
    } else {
        for (int i = 1; i < size(); i++) {
            if (tempNode.equals(newNode)) {
                return i;
            }
            tempNode = tempNode.getNext();
        }
        return -1;
    }

}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: size() description:get the size of the list
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @return Integer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public int size() {
    int size = 1;
    if (firstNode == null) {
        return 0;
    }
    try {
        for (Node n = firstNode; n.getNext() != null; n = n.getNext()) {
            size++;
        }
        return size;
    } catch (NullPointerException e) {
        return size;
    }
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: deepCopy() description: make a deepCoy for this object
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @return String ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
@Override
public ObjectLinkedList deepCopy() {
    ObjectLinkedList newList = new ObjectLinkedList();
    Node currentNode = firstNode;

    for (int i = 0; i < size(); i++) {
        Node newNode = new Node(currentNode.getValue());
        newList.add(i, newNode);
        currentNode = currentNode.getNext();
    }

    return newList;

}

}

下面是使用 Junit 测试的方法

package numberlist.primitivelist.objectlist;

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;


public class ObjectLinkedListTest {

ObjectLinkedList list;
Money m1, m2;
Node node1, node2;

public ObjectLinkedListTest() {

}

@Before
public void setUp() {
    list = new ObjectLinkedList();
    m1 = new Money(5, (byte) 6);
    node1 = new Node(m1);
    list.add(0, node1);

    m2 = new Money(2, (byte) 4);
    node2 = new Node(m2);
    list.add(1, node2);
}

/**
 * Test of add method, of class ObjectLinkedList.
 */
@Test
public void testAdd() {
    assertEquals(list.get(0), node1);
}

/**
 * Test of removeAt method, of class ObjectLinkedList.
 */
@Test
public void testRemoveAt() {
    list.removeAt(1);
    assertNull(list.get(1));
}

/**
 * Test of remove method, of class ObjectLinkedList.
 */
@Test
public void testRemove() {
    list.remove(m2);
    assertNull(list.get(1));
}

/**
 * Test of get method, of class ObjectLinkedList.
 */
@Test
public void testGet() {
}

/**
 * Test of toString method, of class ObjectLinkedList.
 */
@Test
public void testToString() {
}

/**
 * Test of find method, of class ObjectLinkedList.
 */
@Test
public void testFind() {
    assertEquals(list.find(m1), 0);
    assertEquals(list.find(m2), 1);
}

/**
 * Test of size method, of class ObjectLinkedList.
 */
@Test
public void testSize() {
    assertEquals(list.size(), 2);
}

/**
 * Test of deepCopy method, of class ObjectLinkedList.
 */
@Test
public void testDeepCopy() {

}

}

这是我得到的错误:

Error here

我的节点类:

package numberlist.primitivelist.objectlist;

public class Node {

private Node nextNode;
private Object obj;

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: Node() description: constructor
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @param obj set the value
 */
public Node(Object obj) {
    this.obj = obj;
    this.nextNode = null;
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: getValue() description: get the value of object
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @return return the object
 */
public Object getValue() {
    return this.obj;
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: setValue() description: setValue for the Node
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @param obj return the value
 */
public void setValue(Object obj) {
    this.obj = obj;
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: getValue() description: get the next value of the currentNode
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @return return next node
 */
public Node getNext() {
    if (nextNode != null) {
        return this.nextNode;
    } else {
        return null;
    }
}

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Method: setNext() description: set next value for the Node
 *
 * @author Jinyu Wu Date: 2017/2/4
 * @param node set next node
 */
public void setNext(Node node) {
    this.nextNode = node;
}

}

【问题讨论】:

  • Node是如何定义的?
  • 另外,您是如何尝试调试代码的?你的发现是什么,你能提供一小段代码仍然表现得很奇怪吗?

标签: java data-structures collections linked-list nodes


【解决方案1】:

我假设这是为了练习或作业,java 已经有LinkedList 的通用实现see the api docs

您可能会在 java helpul 中找到关于数据结构的众多 texts 之一,尽管它们的实现通常使用泛型而不是 Object


对于您的具体问题,您注意到在您调用的 testAdd 方法中

assertEquals(list.get(0), m1);

这是将NodeMoney 对象进行比较,该对象总是会失败。

你可以assertEquals(list.get(0).getValue(), m1); 除非你将get() 方法更改为返回Node 而不是现在的Object,否则这将不起作用。

您在其他测试中遇到类似问题,其中list.get() 返回Node,而不是该节点中的数据。

或者编辑get()方法以返回节点中的数据:

    ...
    } else if (index == 0) {
        return firstNode.getValue();
    } else {
    // etc, you have multiple returns in this method

编辑

您的testRemoveAt() 将在get 方法尝试调用tempNode.getNext().getValue() 时抛出NullPointerException,但在测试删除第二个对象后列表中只有一个Money 对象,因此getNext() 返回null。

编辑 2

熟悉调试器可能对您最有用。也许可以试试netbeans 的视频教程。然后你调查你的异常。例如,运行您的第一个测试给出:

java.lang.AssertionError: 
Expected :Node@4f2410ac
Actual   :Money@722c41f4

这意味着 testAdd() 测试在调用 assertEquals(list.get(0), m1); 时失败

这里需要注意的是assertEquals 的签名首先采用其预期 值,其次是实际 值。所以将该行更改为assertEquals(m1, list.get(0)); 并重新运行测试。

现在的输出是:

java.lang.AssertionError: 
Expected :Money@722c41f4
Actual   :Node@4f2410ac

所以测试期望Money 对象(即m1 参数),但list.get(0) 返回了Node 对象。

要么测试期待错误的东西,要么get() 方法返回错误的东西。我将假设当您调用 list.get(0) 时,您实际上想要返回一个 Money 对象,这意味着测试是正确,我们需要查看 @987654353 的实现@。

你有:

1.  public Object get(int index) {
2.      if (index < 0 || index > size()) {
3.          System.out.println("get(ObjectLinkedList) index out of bound exception");
4.          return null;
5.      } else if (index == 0) {
6.          return firstNode;
7.      } else {
8.          Node tempNode = firstNode;
9.          for (int i = 0; i <= index; i++) {
10.             if (i == index - 1) {
11.                 tempNode = tempNode.getNext();
12.                 return tempNode;
13.             }
14.         }
15.         System.out.println("objectLinkedList get method nothing found");
16.         return null;
17.      }
18.  }

在第 6 行和第 12 行,您可以看到问题:当我们真正想要 Money 时,函数返回了 Node;或者更具体地说,Node 作为对象的值。因此可以对这些行进行以下更改

6.     return firstNode.getValue();

12.    return tempNode.getValue();

然后再次运行testAdd 它应该可以通过。

这可能不会修复代码中的所有错误,但它可以让您了解查找问题所要遵循的步骤。

您的代码格式正确,您已努力将 javadoc 放在您的函数中,并且您很坚持。干得漂亮,继续努力。

【讨论】:

  • 您好,我接受了您的建议,但现在我遇到了这些错误。我更新了我的问题,你能再拍一次吗?谢谢
  • @JINYUWU 确定您使用的是什么 IDE?
  • 我正在使用 NetBean
  • 谢谢,我按照你的做法,它通过了。但是我的 removeAt 和 remove 方法有什么错误吗?因为我不断得到NPE
  • 嗨@JINYUWU。我提到这可能发生在我之前的第一次编辑中。这是因为代码试图在null 节点上调用getValue()。调试是一项非常有价值的技能,可以通过实践最好地学习,我建议您解决其他错误。
【解决方案2】:

问题出在size() 方法中,您没有考虑两种极端情况:

  1. 当列表为空时(你会因为尝试执行n.getNext()而获得NPE

  2. 当列表中只有一个节点时(它没有“下一个”,所以它会返回零而不是 1)

您可以通过在方法的开头添加以下内容来轻松修复它:

public int size() {
        int size = 1;
        if (firstNode == null) {
            return 0;
        }
        try {...

方法add 中还有另一个错误。 for 循环不必要地复杂,并且不能处理一些边缘情况。修改为:

public void add(int index, Object obj) {
    Node tempNode = firstNode;
    Node currentNode = new Node(obj);
    if (index < 0 || index > size()) {
        System.out.println("add(ObjectLinkedList) index out of bound exception: " + index + "; size: " + size());
    } else if (index == 0) {
        firstNode = currentNode;
    } else {
        for (int i = 0; i < index-1; i++) {
            tempNode = tempNode.getNext();
        }
        tempNode.setNext(currentNode);
    }
}

并且代码将起作用。

此外,我还将“升级”toString 方法为:

@Override
public String toString() {
    Node tmp = firstNode;
    String res = "" + firstNode;
    while (tmp.getNext() != null) {
        tmp = tmp.getNext();
        res += "," + tmp;
    }
    return "ObjectLinkedList{" + res + "}";
}

这样,当您打印列表时,您将能够看到所有元素,而不仅仅是第一个。

【讨论】:

  • 添加代码后我得到了 1。它应该是 2
  • 那是因为您在add 中有另一个错误。查看更新的答案。
  • 我像你一样修改了我的代码,但我仍然收到错误。现在,我的 add、find、removeAt 和 remove 方法有问题。我认为问题在于我的 size() 方法。但我找不到错误
  • @JINYUWU 有什么问题吗?尽量提供更多细节,否则很难为您提供帮助。
猜你喜欢
  • 2018-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 2020-06-27
  • 2017-01-24
  • 1970-01-01
相关资源
最近更新 更多