Before we begin...

  • Do not memorize --- understand what needs to be done and how to achieve it

  • Notations:

    • I will high light the (reference) variable that must be updated with this color

  • Handling edge case(s):

    • It happens very often that a different (reference) variable must be updated for some special ("edge") cases

      • We must look for (= test) the edge cases and handle (= process) them separately

    • Often, the edge cases are

      • The empty list
        ( Test:   first == null )

      • A list that contains only 1 element
        ( Test:   first.next == null )

Inserting an item at the front of the linked list

The effect of addFirst(item) --- inserting item at the front of a linked list:

  • Example: the linked list before the insertion of the String item "to":

  • The linked list after the insertion of "to":

    This is what needs to be done   (look for the high lighted links in the figure)

Implementation of addFirst()

The implementation of the addFirst(T item) method:

  • Let's write the addFirst() method: (This is how to achieve it)

       // Inserts a new node at the beginning of this list
       // take in generic item; Nodes are generic
       public void addFirst(T item)
       {
          Node<T> newNode = new Node<T>(item, oldFirst);
    
          first = newNode;
       }

Implementation of addFirst()

The implementation of the addFirst(T item) method:

  • Create a new Node that stored item and references to the correct next node:

       // Inserts a new node at the beginning of this list
       // take in generic item; Nodes are generic
       public void addFirst(T item)
       {
          Node<T> newNode = new Node<T>(item, first);
    
          first = newNode;
       }

Implementation of addFirst()

The implementation of the addFirst(T item) method:

  • Make the newNode the first element in the linked list (by updating first):

       // Inserts a new node at the beginning of this list
       // take in generic item; Nodes are generic
       public void addFirst(T item)
       {
          Node<T> newNode = new Node<T>(item, first);
    
          first = newNode;
       }

    Done. ( Ignore the help variable newNode when reading the linked list content)

Implementation of addFirst()

Check if algorithm is correct for edge case(s):

  • Run the code for the edge case(s):

       // Inserts a new node at the beginning of this list
       // take in generic item; Nodes are generic
       public void addFirst(T item)
       {
          Node<T> newNode = new Node<T>(item, first);
    
          first = newNode;
       }

Implementation of addFirst()

Check if algorithm is correct for edge case(s):

  • Step 1:

       // Inserts a new node at the beginning of this list
       // take in generic item; Nodes are generic
       public void addFirst(T item)
       {
          Node<T> newNode = new Node<T>(item, first);
    
          first = newNode;
       }

Implementation of addFirst()

Check if algorithm is correct for edge case(s):

  • Step 2:

       // Inserts a new node at the beginning of this list
       // take in generic item; Nodes are generic
       public void addFirst(T item)
       {
          Node<T> newNode = new Node<T>(item, first);
    
          first = newNode;
       }

    It works --- no need to hanlde edge cases.

Removing an item at the front of the linked list

The effect of removeFirst() --- Removing item at the front of a linked list:

  • Example: the linked list before the removal of the String item "to":

  • The linked list after the removal of "to":

    Note:

    • The removeFirst() will also return the item in the list element that was removed (in example: returns "to")

Implementation of removeFirst()

The implementation of the removeFirst() method:

  • Let's write the removeFirst() method:

       // Removes and returns the first element (item) in the list.
       // returns generic type
       public T removeFirst()
       {
          if(isEmpty())
          {
             throw new NoSuchElementException();
          }
    
          T toReturn = first.item;
          first = first.next;
          return toReturn;
       }   

Implementation of removeFirst()

The implementation of the removeFirst() method:

  • Save the return value in toReturn:

       // Removes and returns the first element (item) in the list.
       // returns generic type
       public T removeFirst()
       {
          if(isEmpty())
          {
             throw new NoSuchElementException();
          }
    
          T toReturn = first.item;
          first = first.next;
          return toReturn;
       }  

Implementation of removeFirst()

The implementation of the removeFirst() method:

  • Unlink the first list element:

       // Removes and returns the first element (item) in the list.
       // returns generic type
       public T removeFirst()
       {
          if(isEmpty())
          {
             throw new NoSuchElementException();
          }
    
          T toReturn = first.item;
          first = first.next;
          return toReturn;
       }  

Implementation of removeFirst()

The implementation of the removeFirst() method:

  • Return the saved return value:

       // Removes and returns the first element (item) in the list.
       // returns generic type
       public T removeFirst()
       {
          if(isEmpty())
          {
             throw new NoSuchElementException();
          }
    
          T toReturn = first.item;
          first = first.next;
          return toReturn;
       }  

Implementation of removeFirst()

Check if algorithm is correct for edge case(s):

  • Run the code for the edge case(s):

       // Removes and returns the first element (item) in the list.
       // returns generic type
       public T removeFirst()
       {
          if(isEmpty())
          {
             throw new NoSuchElementException();
          }
    
          T toReturn = first.item;
          first = first.next;
          return toReturn;
       }  

Implementation of removeFirst()

Check if algorithm is correct for edge case(s):

  • Step 1:

       // Removes and returns the first element (item) in the list.
       // returns generic type
       public T removeFirst()
       {
          if(isEmpty())
          {
             throw new NoSuchElementException();
          }
    
          T toReturn = first.item;   // first = null --> crash !
          first = first.next;
          return toReturn;
       } 

    How to handle this Edge case ? --- we report a NoSuchElementException

Implementation of removeFirst()

The complete removeFirst( ) method:

  • The removeFirst( ) method:

       // Removes and returns the first element (item) in the list.
       // returns generic type
       public T removeFirst()
       {
          if( isEmpty() )
          {
             throw new NoSuchElementException();
          }
    
          T toReturn = first.item;   
          first = first.next;
          return toReturn;
       } 

DEMO: 02-insert+remove-front/Demo.java + GenericLinkedList.java

Garbage...

  • Notice the final state of the removeFirst( ) method:

  • Remove the temporary help variable toReturn to make things clearer:

  • Notice that the first node is not referenced to by any permanent variables

    • Such objects are known as garbage

    • Objects that become garbage are inaccessible and unusable in the program

Summary

  • Review of the SumpleList interface:

    interface SimpleList<T>  // A list must implement these methods 
    {
        public boolean isEmpty();
    
        public T getFirst();
        public T getLast();
    
        public void addFirst(T item);
        public T removeFirst();
    
        public void addLast(T item);
        public T removeLast();
    
        public T get(int pos);
        public void remove(T key);
    } 

  • So far, we have implemented:

    • isEmpty(), addFirst() and removeFirst()

  • We will study the addLast() and removeLast() methods next