-2

I'm implementing a linked list for a course online, and there seems to be something wrong with my add function. When I try to add the first element, the Eclipse prints null, and for a second element Eclipse shows an error. (I'm assuming because the first element was never added, so there can't be a second one.)

This is the implementation of my linked list:

    package textgen;

    import java.util.AbstractList;

    public class MyLinkedList<E> extends AbstractList<E> {
        LLNode<E> head;
        LLNode<E> tail;
        int size;

        /** Create a new empty LinkedList */
        public MyLinkedList() {

            size = 0;

            head = new LLNode<E>();
            tail = new LLNode<E>();
            head.next = tail;
            tail.prev = head;

        }

        /**
         * Appends an element to the end of the list
         * @param element The element to add
         */
        public boolean add(E element ) 
        {

            add(size, element);

            return false;
        }

        /** Get the element at position index 
         * @throws IndexOutOfBoundsException if the index is out of bounds. */
        public E get(int index)  throws IndexOutOfBoundsException
        { 

            if(index >= this.size){
                throw new IndexOutOfBoundsException("Your index is out of bounds!");
            }

            LLNode<E> lGet = head;
            for(int i = 0; i < index + 1; i++){
                lGet = lGet.next;
            }

            return  lGet.data;   
        }


        public void printList(){

            LLNode lTemp = head;

            while(lTemp.next != tail){
                System.out.println(lTemp.next.data);
                lTemp = lTemp.next;
            }
        }




        /**
         * Add an element to the list at the specified index
         * @param The index where the element should be added
         * @param element The element to add
         */

        public void add(int index, E element )  throws IndexOutOfBoundsException
        {
            if(index > this.size){   
                throw new IndexOutOfBoundsException("Oops!  Out of bounds!");
        }

                else{
                    LLNode<E> nAdd = new LLNode<E>(element);
                    LLNode<E> nIt = null;


                    if(index <= size/2)  //   if  the index is closer to the start from the beginning of the list
                {
                    nIt = head;

                        for(int i = 0; i < index + 1; i++){
                            nIt = nIt.next;
                        }
                    }


                else {

                    nIt = tail;

                        for(int i = this.size; i > index; i--){
                            nIt = nIt.prev;
                        }

                    }

                    nIt.prev.next.prev = nAdd;    
                    nAdd.next = nIt.prev.next;
                    nIt.prev.next = nAdd;
                    nAdd.prev = nIt.prev;

            size++;
                }   

        }


        /** Return the size of the list */
        public int size()      

        {
            return size;
        }

        /** Remove a node at the specified index and return its data element.
         * @param index The index of the element to remove
         * @return The data element removed
         * @throws IndexOutOfBoundsException If index is outside the bounds of the list
         * 
         */
        public E remove(int index) 
        {
            // TODO: Implement this method



            size--;

            return null;
        }

        /**
         * Set an index position in the list to a new element
         * @param index The index of the element to change
         * @param element The new element
         * @return The element that was replaced
         * @throws IndexOutOfBoundsException if the index is out of bounds.
         */
        public E set(int index, E element) 
        {
            // TODO: Implement this method
            return null;
        }   
    }

    class LLNode<E> 
    {
        LLNode<E> prev;
        LLNode<E> next;
        E data;

        public LLNode(){
            this.data = null;
            this.prev = null;
            this.next = null;
        }

        public LLNode(E e) 
        {
            this.data = e;
            this.prev = null;
            this.next = null;
        }

    }

This is the main:

package textgen;

public class fixAdd {


    public static void main(String [] Arg){

        MyLinkedList<String>  ll = new MyLinkedList<String>();
        ll.add(0, "happy");
    ll.add(1, "gilda");
        System.out.println(ll);

    }
}

And this is the error printed:

Exception in thread "main" java.lang.NullPointerException
    at textgen.MyLinkedList.get(MyLinkedList.java:57)
    at java.util.AbstractList$Itr.next(Unknown Source)
    at java.util.AbstractCollection.toString(Unknown Source)
    at java.lang.String.valueOf(Unknown Source)
    at java.io.PrintStream.println(Unknown Source)
    at textgen.fixAdd.main(fixAdd.java:11)

I've gone over my add method a number of times, and compared it to other implementations I found online, and everything seems in order. I'm totally confused and would appreciate any help. Thanks!

Tova
  • 25
  • 1
  • 3
  • 1. Please indent your code - it's very difficult to read. 2. please post only the relevant code, i.e. if "remove()" is not part of the question - omit it. – Nir Alfasi Jan 28 '16 at 18:14
  • Your exception states clearly that the NPE is being thrown from your `get` method, not your `add` method. – DavidS Jan 28 '16 at 18:16
  • doesn't List have a size() of its own?? why do you need an extra size variable? – gpasch Jan 28 '16 at 18:21
  • 1
    Possible duplicate of [What is a Null Pointer Exception, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-null-pointer-exception-and-how-do-i-fix-it) – Atri Jan 28 '16 at 18:22
  • @Atri many Java questions here in SO deal with NPE and Index out of bounds, but each question has different context... – Nir Alfasi Feb 01 '16 at 16:12
  • @alfasin, I understand that. I just wanted to point OP to this post as a "possible" duplicate as it might help the OP resolve the issue. – Atri Feb 01 '16 at 18:36

3 Answers3

1

You should try to implement a simpler add first, instead of doing the size / 2 optimization.

There are several problems with your code:

  • don't create dummy nodes at initialization, initialize them with null
  • your loop in get method should be for(int i = 0; i < index; i++)
  • your aren't updating the size in your add method

EDIT: Changed add method to cover all cases:

public void add(int index, E element)
{
    if (index > size)
    {
        throw new IndexOutOfBoundsException("Oops!  Out of bounds!");
    }

    LLNode<E> node = new LLNode<E>(element);

    //Add first and last
    if(size == 0)
    {
        head = tail = node;
    }
    else
    {
        //Add first
        if(index == 0)
        {
            node.next = head;
            head.prev = node;
            head = node;
        }

        //Add last
        else if(index  == size)
        {
            node.prev = tail;
            tail.next = node;
            tail = node;
        }

        //Add between
        else
        {
            LLNode<E> current = this.head;

            for(int i = 0; i < index; i++)
            {
                current = current.next;
            }
            node.next = current;
            node.prev = current.prev;
            current.prev.next = node;
        }
    }
    size++;
}
Bifz
  • 403
  • 2
  • 9
  • @someUser I don't think so. `current` should end up being the element after the inserted node. If give index 0, you will not enter the loop, giving `current = head`. If you give index 1, you will run once, giving `current = head.next`, etc... – Bifz May 15 '17 at 09:19
0

Multiple issues with this implementation:

  1. You're setting both head and tail to be empty Nodes when you initialize the list (constructor). You shouldn't do that, it makes your list to be of size two with two null elements.
  2. The exception is thrown from the printing in the main which, in turn, calls your get() method (by calling AbstractList.toString())
  3. In add(E element) you're calling add(size, element); and you pass the size as the index, later on you check if if(index > this.size) which is practically asking if size > size - makes no sense.
  4. In remove() implementation you just decrease the size - this is not good enough, you should also move the tail backwards (and if the list is of size 1 - handle the head as well).
  5. The is the main issue: the logic of insertion in the following lines is incorrect:

nIt.prev.next.prev = nAdd;    
nAdd.next = nIt.prev.next;
nIt.prev.next = nAdd;
nAdd.prev = nIt.prev;

Two suggestions:

  • Don't inherit from AbstractList - after all you're creating your own implementation
  • Start simple, forget about tail or about trying to insert from the end for better efficiency. Only after you have a simple implementation working - try to improve it.
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • Hello, thanks for the detail suggestions. Two things that I'm not clear about - what should I set head and tail to if not null, when I'm first setting up an empty list? Secondly, what is the logical discontinuity (in what you said was the main issue)? If nIt is set to tail, and tail.prev becomes nAdd, doesn't nIt.prev remain head until I explicitly change it? Or is there another problem? – Tova Feb 08 '16 at 08:42
  • 1. there's nothing wrong in setting both head and tail to null when you instantiate the list, but you are not doing so - you are setting them to an empty node - these are two different things! 2. The logic of adding a node is something that you can easily [google](http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/doubly_linked.html) and compare. to what you're doing. – Nir Alfasi Feb 08 '16 at 15:58
-1

Try the following code:

public void insert(int index, T item)
{
if(index == size())
{
    add(item);
}
else if(index == 0)
{
    MyNode<T> temp = new MyNode<T>();
    temp.data = item;
    temp.next = head;
    head.previous = temp;
    head = temp;
    count++;
}
temp = head;
for(int i = 0; i < index-1; i++)
{
    temp = temp.next;
    MyNode<T> myNode = new MyNode<T>();
    myNode.data = item;
    myNode.next = temp.next;
    temp.next = myNode;
    count++;
}
}
GroundIns
  • 541
  • 1
  • 5
  • 11