Java Iterator中的单链接列表实现

时间:2016-10-16 20:46:59

标签: java linked-list iterator singly-linked-list iterable

我正在用Java编写一个简单的Bag实现。我正在实施Iterable并撰写自己的LinkedList迭代器。所以我在绞尽脑汁;我正在尝试向链表添加元素。我有一个有效的实现(add()函数中注释掉的代码)。但是,我不明白为什么以下代码不起作用:

current.item = item;
Node<T> nextNode = new Node<T>();
current.next = nextNode;
current = nextNode;

因此,假设列表为空并且当前头部已初始化但没有项目或下一个:我将项目分配给当前项目,创建一个新节点,将其设置为当前的下一个并更改当前(头部)到我刚刚创建的节点。在列表中添加两个项目,我打印出后代的对象:

  

当前:Bag $ Node @ 4524411f next: Bag $ Node @ 401e7803

     

目前: Bag $ Node @ 401e7803 下一篇:Bag $ Node @ 10dba097

     

当前:Bag $ Node @ 10dba097 next: Bag $ Node @ 1786f9d5

     

当前: Bag $ Node @ 1786f9d5 下一篇:Bag $ Node @ 704d6e83

至少对我来说,看起来很清楚,每次都很好地设置下一个新节点。我将所有四个元素添加到包中,但该项丢失并为每个索引返回null。 toArray()函数显示[null, null, null, null]

我确信这是一件非常简单的事情。以下是整个实施。

import java.util.Iterator;

public class Bag<T> implements Iterable<T> {
    private Node current;
    //Node<T> head;
    private int numberofProducts;
    T[] myBag;
    int defaultCapacity;

    public Iterator<T> iterator() {
        return new ListIterator<T>(current);
    }

    public Bag(int defaultCapacity) {
        this.current = new Node<T>();
        this.numberofProducts = 0;
        this.defaultCapacity = defaultCapacity;
    }

    public void add(T item) {
        if(isFull()) {
            System.out.println("bags full, yo");
            return;
        }

        current.item = item;
        Node<T> nextNode = new Node<T>();
        current.next = nextNode;
        current = nextNode;

        numberofProducts++;

    //Node<T> nextNode = current;
    //current = new Node<T>();
    //current.item = item;
    //current.next = nextNode;
    //numberofProducts++;


    }

    public Object[] toArray() {
        Object[] array = new Object[size()];

        int i = 0;
        Node<T> node = current;
        //Node<T> node = head;
        while(node.next != null) {
            array[i] = node.item;
            node = node.next;
            i++;
        }

        return array;
    }

    public boolean isEmpty() {
        return this.numberofProducts <= 0;
    }

    public boolean isFull() {
        return this.numberofProducts >= defaultCapacity;
    }

    public int size() {
        return this.numberofProducts;
    }

    private class Node<T> {
        private T item;
        private Node<T> next;
    }


    private class ListIterator<T> implements Iterator<T> {

        private Node<T> current;

        public  ListIterator(Node<T> first) {
            current = first;
        }

        public boolean hasNext() {

            return current != null;
        }

        public T next() {
            if(hasNext()) {
                T item = current.item;
                current = current.next;
                return item;
            }
            return null;
        }

        public void remove() {

        }
    }
}

3 个答案:

答案 0 :(得分:1)

项目值不会丢失。问题是你忘记了链表的头部。您的current变量已经跟踪尾部,并且由于toArray()方法从current开始,while循环永远不会执行,因为在尾部元素之后没有元素列表。

因此,您最终会得到一个默认初始化Object值数组,即null

要解决此问题,您需要另一个实例变量来跟踪列表的头部,这就是您在toArray()方法中使用的内容。

答案 1 :(得分:1)

从我所看到的,它不作为链接列表的原因是因为你没有保留对添加的第一个元素的引用。而是保留对添加的最后一个(current)元素的引用。

您可以通过添加第一个元素的类字段引用来解决此问题 T head

然后在add()方法中,将head设置为您创建的Node。然后,当您构建ListIterator时,将head作为参数传递。

您可以将add(T item)更改为显示如下:

public void add(T item) {
    if (!isFull()) {
        Node<T> toAdd = new Node<>();
        toAdd.item = item;
        current.next = toAdd;
        current = toAdd;
        if (head == null) {
            head = toAdd;
        }
    }
}

然后将类字段Node<T> head添加到Bag<T>类。

此外,我不确定为什么Node是一个静态类,加上我现在不会涉及的其他一些变化,但我猜这个类目前还不完整。

答案 2 :(得分:1)

问题在于您用add()方法编写的逻辑。每当将新数据添加到Bag时,您的根节点都会更改,并指向Bag的最后一个节点。由于倒数第二个节点为null,因此迭代器不返回任何内容。请参阅to this link,以获取确切的解决方案。