Java:LinkedList findnode()方法和isEmpty()方法

时间:2015-06-15 01:08:21

标签: java junit

我有一个实现可迭代接口的LinkedList类,在LinkedList类中我有一个内部节点类。我有另一个运行JUnit 4的TestLinkedList类。测试类将检查linkedlist类中的所有函数。

这是我的LinkedListClass:

public class LinkedList<T> implements Iterable<T>
{
    public class Node
    {
        private T value;
        private Node next;

        public Node(Node next, T value)
        {
            this.next = next;
            this.value = value;
        }

        /**
         * Returns the next node in the linked list.
         * 
         * @return The next node in the linked list.
         */
        public Node getNext()
        {
            return this.next;
        }

        /**
         * Set the next node in the linked list.
         * 
         * @param next
         *            The node to be added to the LinkedList.
         */
        public void setNext(Node next)
        {
            this.next = next;
        }

        /**
         * Return the value contained in the node.
         * 
         * @return the value contained in the node.
         */
        public T getValue()
        {
            return this.value;
        }

        /**
         * Set the node with the value given.
         * 
         * @param value
         *            The value to be placed in the node.
         */
        public void setValue(T value)
        {
            this.value = value;
        }

        public String toString()
        {
            return "Node " + this.value;
        }
    }
    public Node front;
    public LinkedList()
    {
        front = null;
    }


    /**
     * Return the number of elements in the LinkedList
     * 
     * @return The size of the LinkedList
     */
    public int getSize()
    {
        Node current = front;
        int count = 0;
        while (current != null)
        {
            count++;
            current = current.getNext();
        }
        return count;
    }

    /**
     * Return true if the LinkedList is empty, false otherwise
     * 
     * @return true if the LinkedList is empty, false otherwise
     */
    public boolean isEmpty()
    {
        return front == null;
    }

    /**
     * Insert a node at the front of the linked list. The first variable should now point to this node. Wrap it in a
     * node and add it to the list. Do not add the Node if it already exists in the list.
     * 
     * @param node
     *            The node to be inserted into the linked list.
     * @return true if inserted, false if already in list and cannot be inserted.
     */
    public boolean insertFront(T element)
    {
            Node current = front;
            boolean isExist = false;
            while (current != null)
            {
                if (current.getValue().equals(element))
                {
                    isExist = true;
                }
                current = current.getNext();
            }
            if (isExist == true)
            {
                return false;
            }
            else
            {
                front = new Node(front, element);
                return true;    
            }
    }

    /**
     * Insert a node at the back of the linked list. Wrap it in a node and add it to the list. Do not add the Node if it
     * already exists in the list.
     * 
     * @param node
     *            The node to be inserted into the linked list.
     * @return true if inserted, false if already in list and cannot be inserted.
     */

    public boolean insertBack(T element)
    {
        if (front == null)
        {
            insertFront(element);
            return true;
        }
        else
        {
            Node current = front;
            Node temp = current;
            while (current!= null && !current.getValue().equals(element))
            {
                current = current.getNext();
            }
            if (current != null)
            {
                return false;
            }
            else
            {
                while(temp.getNext() != null)
                {
                    temp = temp.getNext();
                }
                temp.setNext(new Node(null, element));
                return true;
            }
        }
    }

    /**
     * Insert the given node after the currentNode given. Wrap it in a node and add it in a position after the node
     * specified by the variable {@code currentNode}. Throws a NodeNotFoundException if it can't found the node given.
     * Do not add the Node if it already exists in the list.
     * 
     * @param currentNode
     *            The node to look for to add the given node behind.
     * @param node
     *            The element to be inserted into the linked list.
     * @throws NodeNotFoundException
     *             Thrown if the element given is not found
     * @return true if inserted, false if already in list and cannot be inserted.
     */

    public boolean insertAfter(T currentElement, T element) throws NodeNotFoundException
    {
        Node current = front;
        Node check = current;
        while (current != null && !current.getValue().equals(currentElement))
        {
            current = current.getNext();
        }
        if (current == null)
        {
            throw new NodeNotFoundException("" + currentElement);
        }
        else
        {
            while(check != null && !check.getValue().equals(element))
            {
                check = check.getNext();
            }
            if (check != null)
            {
                return false;
            }
            else
            {
                current.setNext(new Node(current, element));
                return true;
            }
        }
    }

    /**
     * Insert the given node before the currentNode given. Wrap it in a node and add it in a position after the node
     * specified by the variable {@code currentNode}. Throws a NodeNotFoundException if it can't found the node given.
     * Do not add the Node if it already exists in the list.
     * 
     * @param currentNode
     *            The node to look for to add the given node in front of.
     * @param node
     *            The element to be inserted into the linked list.
     * 
     * @throws NodeNotFoundException
     *             Thrown if the element given is not found
     * @return true if inserted, false if already in list and cannot be inserted.
     */

    public boolean insertBefore(T currentElement, T element) throws NodeNotFoundException
    {
        if (front == null)
        {
            throw new NodeNotFoundException("" + currentElement);
        }
        if (front.getValue().equals(currentElement))
        {
            insertFront(element);
            return true;
        }
        Node previous = null;
        Node current = front;
        Node check = current;
        while (current != null && !current.getValue().equals(currentElement))
        {
            previous = current;
            current = current.getNext();
        }
        if (current == null)
        {
            throw new NodeNotFoundException("" + currentElement);
        }
        else
        {
            while (check != null && !check.getValue().equals(element))
            {
                check = check.getNext();
            }
            if (check != null)
            {
                return false;
            }
            previous.setNext(new Node(current, element));
            return true;
        }
    }

    /**
     * Remove the node matches the given element. Return the element that is removed. Throws NodeNotFoundException if
     * the element is not found.
     * 
     * @param element
     *            The element to find and remove.
     * @return Return the node that contains the element that was removed.
     * @throws NodeNotFoundException
     *             Thrown if the element to be found can't be found.
     */
    public T remove(T element) throws NodeNotFoundException
    {
        if(front == null)
        {
            throw new NodeNotFoundException(element.toString());
        }

           if( front.getValue().equals(element) )
           {
              front = front.getNext();
              return element;
           }

           Node current  = front;
           Node previous = null;

           while(current != null && !current.getValue().equals(element) )
           {
              previous = current;
              current = current.getNext();
           }

           if(current == null)
           {
               throw new NodeNotFoundException(element.toString());
           }

           previous.setNext(current.getNext());
           return element;
    }

    /**
     * Remove all nodes in the LinkedList, return all nodes in an ArrayList.
     * 
     * 
     * @return Returns all nodes in an ArrayList.
     */

    public ArrayList<T> removeAll() throws NodeNotFoundException
    {
        Node current = front;
        ArrayList<T> arrayList = new ArrayList<T>();

        while (current != null)
        {
            arrayList.add(current.getValue());
            current = current.getNext();
        }
        front = null;
        return arrayList;
    }

    /**
     * Return true if the element passed in is in the linked list.
     * 
     * @param element
     *            The element to check for.
     * @return true if the element exists in the linked list, false otherwise.
     */
    public boolean contains(T element)
    {
        Node current = front;
        while (current != null)
        {
            if (current.value.equals(element))
            {
                return true;
            }
            current = current.getNext();
        }
        return false;
    }

    /**
     * Find an element and return it if it is found, otherwise return null
     * 
     * @param element
     *            The element to look for.
     * @return The element if found, null if not.
     */
    public T findElement(T element)
    {
        Node check = front;
        while (check != null && !check.getValue().equals(element))
        {
            check = check.getNext();
        }
        if (check == null)
        {
            return null;
        }
        else
        {
            return check.getValue();
        }
    }

    /**
     * Find an element and return it if it is found, otherwise return null
     * 
     * @param element
     *            The element to look for.
     * @return The element if found, null if not.
     */
    public Node findNode(T element)
    {
        if(contains(element) == false)
        {
            return null;
        }
        else
        {
            Node check = front;
            while (check != null && !check.getValue().equals(element))
            {
                check = check.getNext();
            }
            return check;
        }
    }

    /**
     * Converts the LinkedList to an ArrayList.
     * 
     * @return An ArrayList containing all elements that are contained within the linked list.
     */
    public ArrayList<T> convert()
    {
        Node current = front;
        ArrayList<T> arrayList = new ArrayList<T>();

        while (current != null)
        {
            arrayList.add(current.getValue());
            current = current.getNext();
        }
        return arrayList;
    }

    /**
     * Return the linked list as a string in the format element -> element -> element. For example
     * "first -> second -> third"
     * 
     * @return This linked list in the form of a string.
     */
    @Override
    public String toString()
    {
        Node current = front;
        String s = "";

        while (current.getNext() != null)
        {
            s += current.getValue() + "->";
            current = current.getNext();
        }
        s += "" + current.getValue();
        return s;
    }
    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Iterable#iterator()
     */
    @Override
    public Iterator<T> iterator()
    {
        return new LinkedListIterator<T>(new LinkedList<T>());
    }
}

这是我的LinkedListIterator类:

public class  LinkedListIterator<T> implements Iterator<T>
{
    LinkedList<T>.Node previous;
    LinkedList<T>.Node current;
    public LinkedListIterator(LinkedList<T> list)
    {
        current = list.front;
    }
    /*
     * (non-Javadoc)
     *
     * @see java.util.Iterator#hasNext()
     */
    @Override
    public boolean hasNext()
    {
        return current != null;
    }

    /*
     * (non-Javadoc)
     *
     * @see java.util.Iterator#next()
     */
    @Override
    public T next()
    {
        if (!hasNext())
        {
            return null;
        }
        T temp = current.getValue();
        previous = current;
        current = current.getNext();
        return temp;
    }

    /*
     * (non-Javadoc)
     *
     * @see java.util.Iterator#remove()
     */
    @Override
    public void remove()
    {
        previous.setNext(current.getNext());
    }
}

这是我的TestLinkedList类:

public class TestLinkedList
{
    private static String FIRST = "First";
    private static String SECOND = "Second";
    private static String THIRD = "Third";
    private static String FOURTH = "Fourth";
    private static String MISSING = "Missing";
    private static String TEST_STRING = "First->Second->Third->Fourth";
    private static String TEST_ARRAY = "[First,Second,Third,Fourth]";
    private LinkedList<String> testList;

    @Before
    public void setUp() throws NodeNotFoundException
    {
        testList = new LinkedList<String>();
    }

    @Test
    public void testNextAndHasNext() throws NodeNotFoundException
    {
        insertAll(testList);
        assertTrue("Next/HasNext failed", compareListToStrings(testList, FIRST, SECOND, THIRD, FOURTH));
    }

    @Test
    public void testIsEmpty() throws NodeNotFoundException
    {
        insertAll(testList);
        assertFalse("isEmpty Failed", testList.isEmpty());
        removeViaIterator(testList);
        assertTrue("isEmpty Failed after emptying", testList.isEmpty());
    }

    @Test
    public void testIteratorRemove() throws NodeNotFoundException
    {
        insertAll(testList);
        removeViaIterator(testList);
        Iterator<String> iter = testList.iterator();
        assertFalse("Iterator remove failed", iter.hasNext());
    }

    @Test
    public void testInsertFrontAndBack()
    {
        assertTrue("insertFront failed on first insert", testList.insertFront(FIRST));
        assertTrue("insertFront failed, list has too many elements", compareListToStrings(testList, FIRST));
        assertFalse("insertFront failed, same element added to list", testList.insertFront(FIRST));
        assertTrue("insertBack failed when inserting element not in list", testList.insertBack(FOURTH));
        assertTrue("insertBack failed, list has wrong elements", compareListToStrings(testList, FIRST, FOURTH));
        assertFalse("insertBack failed, same element already added to list", testList.insertBack(FOURTH));
    }

    @Test(expected = NodeNotFoundException.class)
    public void testNodeNotFound() throws NodeNotFoundException
    {
        testList.insertBefore(MISSING, MISSING);
    }

    @Test
    public void testInsertBeforeAndAfter() throws NodeNotFoundException
    {
        testList.insertFront(FOURTH);
        testList.insertFront(FIRST);
        assertTrue("insertBefore failed", testList.insertBefore(FOURTH, THIRD));
        assertTrue("insertBefore failed, list does not have right elements",
                compareListToStrings(testList, FIRST, THIRD, FOURTH));
        assertFalse("insertBeforeFailed on inserting duplicate elements", testList.insertBefore(FOURTH, THIRD));
        assertTrue("insertAfter failed", testList.insertAfter(FIRST, SECOND));
        assertTrue("insertAfter failed, list does not have right elements",
                compareListToStrings(testList, FIRST, SECOND, THIRD, FOURTH));
        assertFalse("insertAfter failed on inserting duplicate elements", testList.insertAfter(FIRST, SECOND));
    }

    @Test
    public void testToStringAndToArray()
    {
        testList.insertFront(FOURTH);
        testList.insertFront(THIRD);
        testList.insertFront(SECOND);
        testList.insertFront(FIRST);
        String listString = testList.toString();
        assertTrue("toString failed", listString.replaceAll("\\s+", "").equals(TEST_STRING));
        String arrayString = testList.convert().toString();
        assertTrue("convert failed", arrayString.replaceAll("\\s+", "").equals(TEST_ARRAY));
    }

    @Test
    public void testContains()
    {
        testList.insertFront(FOURTH);
        testList.insertFront(THIRD);
        testList.insertFront(SECOND);
        testList.insertFront(FIRST);
        assertTrue("Contains failed", testList.contains(FIRST));
    }

    @Test
    public void testFind()
    {
        testList.insertFront(FOURTH);
        testList.insertFront(THIRD);
        testList.insertFront(SECOND);
        testList.insertFront(FIRST);
        String element = testList.findElement(SECOND);
        assertNotNull("find failed, element null", element);
        assertEquals(SECOND, element);
        assertTrue("Find failed", findNode(testList, testList.findNode(SECOND)));
    }

    @Test
    public void testRemove() throws NodeNotFoundException
    {
        testList.insertFront(FOURTH);
        testList.insertFront(THIRD);
        testList.insertFront(SECOND);
        testList.insertFront(FIRST);
        String second = testList.remove(SECOND);
        assertNull("Found Second in list after removal", testList.findNode(SECOND));
        assertEquals(SECOND, second);
    }

    @Test
    public void testRemoveAll() throws NodeNotFoundException
    {
        testList.insertFront(FOURTH);
        testList.insertFront(THIRD);
        testList.insertFront(SECOND);
        testList.insertFront(FIRST);
        ArrayList<String> control = testList.convert();
        ArrayList<String> result = testList.removeAll();
        Iterator<String> iter = testList.iterator();
        assertEquals(control, result);
        assertFalse("RemoveAll Failed", iter.hasNext());
    }

    @Test
    public void testSize()
    {
        assertEquals(0, testList.getSize());
        testList.insertFront(FOURTH);
        testList.insertFront(THIRD);
        testList.insertFront(SECOND);
        testList.insertFront(FIRST);
        assertEquals(4, testList.getSize());
    }

    private static <T> boolean compareListToStrings(LinkedList<T> list, T... values)
    {
        int index = 0;
        Iterator<T> iter = list.iterator();
        while (iter.hasNext())
        {
            if (!values[index].equals(iter.next()))
            {
                return false;
            }
            index++;
        }

        return true;
    }

    private static <T> boolean findNode(LinkedList<T> list, LinkedList<T>.Node n)
    {
        Iterator<T> iter = list.iterator();
        while (iter.hasNext())
        {
            if (n.getValue().equals(iter.next()))
            {
                return true;
            }
        }
        return false;
    }

    private static void insertAll(LinkedList<String> list) throws NodeNotFoundException
    {
        list.removeAll();
        list.insertFront(FOURTH);
        list.insertFront(THIRD);
        list.insertFront(SECOND);
        list.insertFront(FIRST);
    }

    private static <T> void removeViaIterator(LinkedList<T> list) throws NodeNotFoundException
    {
        Iterator<T> iter = list.iterator();
        while (iter.hasNext())
        {
            iter.next();
            iter.remove();
        }
    }
}

测试类有12个测试,其中包括testIsEmpty和testFind。 当我进行测试时,我没有通过这两项测试。 我因为上一个断言而失败了testIsEmpty:

assertTrue("isEmpty Failed after emptying", testList.isEmpty());

由于这个断言,testFind失败了:

assertTrue("Find failed", findNode(testList, testList.findNode(SECOND)));

在TestIsEmpty中,我以为我在迭代器类中实现了remove()函数错误,但我不知道为什么。 testFind我看了函数findNode(),我很确定它没有任何问题。

如果有人可以查看我的代码,那就太好了。

2 个答案:

答案 0 :(得分:1)

在LinkedList中定义iterator()时,您似乎正在创建一个新的LinkedList对象,而不是使用您想要迭代的列表。因此,当您在removeViaIterator()方法中调用Iterator iter = list.iterator()时,它不返回任何数据,并且未在方法中执行while循环。

答案 1 :(得分:0)

findNode(实际上是迭代器)

的问题 我正在打字时

Sambaran spotted this one ...

LinkedList.iterator每次调用时都会创建 new LinkedList,并将 传递给LinkedListIterator构造函数:

return new LinkedListIterator<T>(new LinkedList<T>());

LinkedListIterator将始终(正确地)报告LinkedList为空。该行应改为:

return new LinkedListIterator<T>(this);

isEmpty的问题(也是迭代器)

测试正确---列表为空。 LinkedListIterator.remove永远不会删除第一个Node,因此TestLinkedList.removeViaIterator永远不会完全清空列表。

考虑LinkedListIterator遍历仅LinkedList Node currentNode点到previousnull点(默认情况下)next。在调用迭代器的current方法一次后,null将指向列表末尾previous,而Node将指向唯一Node current } ...现在要删除一次当前的front

现在已经太晚了

front不应该从front 开始,而是在一些非法的“next之前”状态;它应该在第一次调用Node时提前到public class LinkedListIterator<T> implements Iterator<T> { final LinkedList<T> list; LinkedList<T>.Node previous; LinkedList<T>.Node current; boolean canRemove; public LinkedListIterator(LinkedList<T> list) { // Required by remove. this.list = list; // Required by remove. this.canRemove = false; // No change, just making it explicit. this.previous = null; // Bogus "pre-front" Node, for before first call to next. this.current = this.list.new Node(this.list.front, null); } // etc... } 。考虑使用“真实列表之前”存在的虚假list初始化它:

remove

我添加了front字段,因此LinkedList.front可以处理删除previous.next的特殊情况---它必须更新canRemove而不是Iterator

LinkedListIterator.next可以解决其他几个问题......

NoSuchElementException合同问题

当没有下一个元素时,您的null方法应该抛出null。当remove是合法元素值时,它应该返回IllegalStateException尤其是

next方法应在两种情况下引发remove

  

[...]如果尚未调用next方法,或者在上次调用canRemove方法后已调用false方法

那来自Iterator interface's docs。你应该(重新)仔细阅读它们,因为写一个“Iteratorish”非常容易,它可以很好地调试所有 else 是一场噩梦。

true字段可以处理所有这些情况。将其初始化为next。它由true方法设置为next(即使已经false --- remove无关心),并再次设置为remove @Override public void remove() { if (!this.canRemove) { throw new IllegalStateException("Helpful error message."); } // Remove current Node. this.canRemove = false; return; } 方法。 读取的唯一代码是Node方法:

T

其他观察

  1. 您的JavaDoc通常是完全错误的。例如,他们中的许多人声称,当用户真正插入类型 - findNode 元素时,用户可以在列表中插入Node。具有讽刺意味的是,findNode有相反的问题:声称它返回一个元素,当它真正返回LinkedList时。 (在您的测试类中有一个完全不同的 null方法没有帮助。)我停止阅读您的评论,因为它们经常被误导。

  2. 您的if (someNode.getValue().equals(someElement)) { ... }可以存储NullPointerException元素。这很好,如果尴尬的话。什么是好的是,您经常执行类似null的操作,如果该节点存储findElement,则会抛出null

  3. null表示通过返回找到的元素来表示成功,并通过返回findElement(null)来表示失败。但null是一个合法的元素值,因此NodeNotFoundException 总是返回ElementNotFoundException。这是否意味着你找到了它,或者你没有找到它?考虑抛出findElement(或contains?)来表示失败,就像你在别处做的那样。 (另外,IteratorIterator的区别如何?)

  4. 当您不必执行时,您经常遍历整个列表...并且您复制了大部分private int size代码。所以使用getSize! (......一旦修好了。)

  5. 您可以维护一个isEmpty字段,以便与LinkedList.front(和private)一起使用,而不是计算列表中的所有元素。

  6. LinkedList.front应为Node(包含所暗示的所有修改)。

  7. 整个“如果节点已存在于列表中,请不要添加节点。”事情是......而不是列表通常如何表现。它更像是一个集合,而链表是制作集合的一种非常低效的方式。

  8. Don't Repeat Yourself!计算从findNode开始的地点,然后沿着链接的contains向下走。为什么不拨打NodeNode?计算比较两个null元素的位置,或(稍微不同)确定一个可能为空的{{1}}引用是否包含已知元素。用一两个私有方法替换该代码,然后使用它们。 (那个方法会处理我上面提到的{{1}}元素,所以你不会在你的代码中撒上“if-null-else”。)