简体   繁体   中英

Singly Linked List implementation in Java Iterator

I'm writing a simple implementation of a Bag in Java. I am implementing Iterable and writing my own LinkedList Iterator. So I'm racking my brain; I am trying to add elements to the linked list. I have a working implementation (the commented out code in the add() function). However, I do not understand why the following code does not work:

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

So, given that the list is empty and the current head is initialized but has no item or next: I assign item to the current item, create a new node, set it to the current's next and change the current (head) to the node I just created. Adding two items to the list, I printed out the objects for posterity:

current: Bag$Node@4524411f next: Bag$Node@401e7803

current: Bag$Node@401e7803 next: Bag$Node@10dba097

current: Bag$Node@10dba097 next: Bag$Node@1786f9d5

current: Bag$Node@1786f9d5 next: Bag$Node@704d6e83

It looks clearly, to me at least, that the next is getting set with a new node each time just fine. I get all four elements added to the bag, but the item is lost and returns null for each index. The toArray() function shows [null, null, null, null]

I'm sure it's something blindingly simple. Below is the entire implementation.

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() {

        }
    }
}

The item values aren't lost. The problem is that you lose track of the head of the linked list. Your current variable keeps track of the tail already, and since your toArray() method starts at current , the while loop never executes because there are no elements after the tail element of the list.

Consequently, you just end up with an array of default-initialized Object values, ie null .

To fix this, you need another instance variable to keep track of the head of the list, and this is what you'll use in your toArray() method.

From what I can see, the reason it's not acting as a Linked List is because you are not retaining a reference to the first element added. Rather you retain a reference to the last ( current ) element added.

You can resolve this by adding a class field reference the first element added T head

Then in your add() method, set head to the Node you create. Then when you construct your ListIterator, pass head as the parameter.

You can change add(T item) to showing like this:

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;
        }
    }
}

Then add the class field Node<T> head to your Bag<T> class.

Additionally, I'm not sure why Node is a static class, plus a number of other changes I won't get into now, but I guess the class is incomplete at present.

The problem is with your logic written in the add() method. Whenever adding the new data to Bag, your root node is changing and pointing to the last node of your Bag. Since the next to last node is null, that's why the iterator is not returning anything. Refer to this link for the exact solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM