Inserting an item at the end of the linked list

The effect of addLast(item) --- inserting item at the end of a linked list:

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

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

  • Insert at end algorithm:

       (1) Find the last element in the linked list
       (2) Make a new Node with data and link to the last element
    

Algorithm to find the last node in a linked list

  • The algorithm to find the last node in a list is based on list traversal:

    The list traversal algorithm:

       Node<T> current = first;
    
       while ( current != null ) 
       {
           current = current.next;
       }
    
       // We will have visited all nodes in the list
    

Algorithm to find the last node in a linked list

  • To find the last node, we exit the (search) loop when current.next == null:

    Algorithm to find the last node in a list:

       Node<T> current = first;
    
       while ( current != null && current.next != null ) 
       {
           current = current.next;
       }
    
       // current points to the last node
    

Algorithm to find the last node in a linked list

  • Because the list traversal always stops before current == null:

    Algorithm to find the last node in a list can be simplified:

       Node<T> current = first;
    
       while ( current.next != null ) 
       {
           current = current.next;
       }
    
       // current points to the last node
    

Implementation of addLast(item)

 

Let's implement the addLast(item) method:

   // Inserts a new node to the end of this list
   public void addLast(T item)
   {
      if(isEmpty())                     // Edge case: empty list
      {
         (1) Find the last element in the linked list
         (2) Make a new Node with data and link to the last element 
      }
      else
      {
         Node current = first;
         while(current.next!=null)      // Find last lsit element
         {
            current = current.next;
         }
         current.next = new Node(item,null);   // Make list elem + link
      }
   }

Implementation of addLast(item)

 

Start the search at the first node in the linked list:

   // Inserts a new node to the end of this list
   public void addLast(T item)
   {
      if(isEmpty())                     // Edge case: empty list
      {
         (1) Find the last element in the linked list
         (2) Make a new Node with data and link to the last element 
      }
      else
      {
         Node<T> current = first;
         while(current.next!=null)      // Find last lsit element
         {
            current = current.next;
         }
         current.next = new Node<T>(item,null);   // Make list elem + link
      }
   }

Implementation of addLast(item)

 

Find the last element in the linked list:   the next variable in this element is null

   // Inserts a new node to the end of this list
   public void addLast(T item)
   {
      if(isEmpty())                     // Edge case: empty list
      {
         (1) Find the last element in the linked list
         (2) Make a new Node with data and link to the last element 
      }
      else
      {
         Node<T> current = first;
         while ( current.next != null )   // Find last list element
         {
            current = current.next;
         }
         current.next = new Node<T>(item,null);   // Make list elem + link
      }
   }

Implementation of addLast(item)

 

Make a new Node containing the item and next = null (because it will be the last element)

   // Inserts a new node to the end of this list
   public void addLast(T item)
   {
      if(isEmpty())                     // Edge case: empty list
      {
         (1) Find the last element in the linked list
         (2) Make a new Node with data and link to the last element 
      }
      else
      {
         Node<T> current = first;
         while ( current.next != null )   // Find last list element
         {
            current = current.next;
         }
                        new Node<T>(item,null);   // Make list elem
      }
   }

Implementation of addLast(item)

 

Link the new Node to the last element in the list:

   // Inserts a new node to the end of this list
   public void addLast(T item)
   {
      if(isEmpty())                     // Edge case: empty list
      {
         (1) Find the last element in the linked list
         (2) Make a new Node with data and link to the last element 
      }
      else
      {
         Node<T> current = first;
         while ( current.next != null )   // Find last list element
         {
            current = current.next;
         }
         current.next = new Node<T>(item,null);   // Make list elem + link
      }
   }

Implementation of addLast(item)

 

Check for edge case(s):

   // Inserts a new node to the end of this list
   public void addLast(T item)
   {
      if(isEmpty())                     // Edge case: empty list
      {
         
         
      }
      else
      {
         Node<T> current = first;  // null
         while ( current.next != null )   // CRASH (because current = null)
         {
            current = current.next;
         }
         current.next = new Node<T>(item,null);   // Make list elem + link
      }
   }

Implementation of addLast(item)

 

We must handle the edge case separately:

   // Inserts a new node to the end of this list
   public void addLast(T item)
   {
      if( isEmpty() )                     // Edge case: empty list
      {
         first = new Node<T>(item,null); // We studied this before..
         //equivalent: addFirst(item) 
      }
      else
      {
         Node<T> current = first;  // not null
         while ( current.next != null )   
         {
            current = current.next;
         }
         current.next = new Node<T>(item,null);   // Make list elem + link
      }
   }

Removing an item at the end of the linked list

The effect of removeLast() --- removing an item at the end of a linked list:

  • Example: the linked list before the removal of the last node:

  • The linked list after the removal of the last node:

  • Remove at end algorithm:

       (1) Find the predecesor node of the last node
       (2) Unlink the last node from its predecesor node
    

Algorithm to find the predecessor of the last node

  • Recall that we have developed an algorithm to find the last node in a linked list:

       Node<T> current = first;
    
       while ( current.next != null ) 
       {
           current = current.next;
       }
    

    Question:

    • Can we go backward a node to find the predecessor node ???

     

Algorithm to find the predecessor of the last node

  • Recall that we have developed an algorithm to find the last node in a linked list:

       Node<T> current = first;
    
       while ( current.next != null ) 
       {
           current = current.next;
       }
    

    Answer:

    • No, because the (simple) linked list only contain forward links !

    (We can go backward if list also has backward links.... Law of COM)

Algorithm to find the predecessor of the last node

  • We modify the algorithm that finds the last node slightly:

    The algorithm to find the last node is as follows:

    
       Node<T> current = first;
    
       while ( current.next != null ) // Find last list element
       {
    
           current = current.next;
       }
    
    
       // current points to the last node
    

Algorithm to find the predecessor of the last node

  • ... while keeping track of the previous node:

    The algorithm to find the predecessor of the last node is as follows:

       Node<T> previous = first;
       Node<T> current = first;
    
       while ( current.next != null ) // Find last list element
       {
           previous = current; // Keep track of the previous node
           current = current.next;
       }
    
       // previous points to the predecessor node of last node
       // current points to the last node
    

Implementation of removeLast( )

 

Let's implement the removeLast( ) method:

   // Delete the node at the end of this list
   public T removeLast( )
   {  // General case  (take care of edge cases later)
      // Find the last node while remembering the previous node
      Node<T> current = first;
      Node<T> previous = first;
      while( current.next != null )
      {
         previous = current;
         current = current.next;
      }

      // Unlink the last node (from its predecessor)
      previous.next = null;

      // Return item in the last node
      return current.item;
   }

Implementation of removeLast( )

 

Start the search at the first node:

   // Delete the node at the end of this list
   public T removeLast( )
   {  // General case  (take care of edge cases later)
      // Find the last node while remembering the previous node
      Node<T> current = first;
      Node<T> previous = first;
      while( current.next != null )
      {
         previous = current;
         current = current.next;
      }

      // Unlink the last node (from its predecessor)
      previous.next = null;

      // Return item in the last node
      return current.item;
   }

Implementation of removeLast( )

 

Find the last node while remembering its previous node:

   // Delete the node at the end of this list
   public T removeLast( )
   {  // General case  (take care of edge cases later)
      // Find the last node while remembering the previous node
      Node<T> current = first;
      Node<T> previous = first;
      while( current.next != null )
      {
         previous = current;
         current = current.next;
      }

      // Unlink the last node (from its predecessor)
      previous.next = null;

      // Return item in the last node
      return current.item;
   }

Implementation of removeLast( )

 

Unlink the last node from the previous node:

   // Delete the node at the end of this list
   public T removeLast( )
   {  // General case  (take care of edge cases later)
      // Find the last node while remembering the previous node
      Node<T> current = first;
      Node<T> previous = first;
      while( current.next != null )
      {
         previous = current;
         current = current.next;
      }

      // Unlink the last node (from its predecessor)
      previous.next = null;

      // Return item in the last node
      return current.item;
   }

Implementation of removeLast( )

 

Return the item in the last node:

   // Delete the node at the end of this list
   public T removeLast( )
   {  // General case  (take care of edge cases later)
      // Find the last node while remembering the previous node
      Node<T> current = first;
      Node<T> previous = first;
      while( current.next != null )
      {
         previous = current;
         current = current.next;
      }

      // Unlink the last node (from its predecessor)
      previous.next = null;

      // Return item in the last node
      return current.item;
   }

Implementation of removeLast( )

 

Check for edge cases....

   // Delete the node at the end of this list
   public T removeLast( )
   {
      // Detect and handle edge case








      // General case  (take care of edge cases later)
      ... code omitted for brevity...

      (The general case updates previous.next)
   }

Implementation of removeLast( )

 

Edge case 1: empty list....   you cannot remove something from an empty list --- error.

   // Delete the node at the end of this list
   public T removeLast( )
   {
      // Detect and handle edge case
      if( isEmpty() )                         // Edge case 1: empty list
      { // empty list can't remove anything
         throw new NoSuchElementException();
      }




      // General case  (take care of edge cases later)
      ... code omitted for brevity...

      (The general case updates previous.next)
   }

Implementation of removeLast( )

 

Edge case 2: list with a single element ---> removal results in an empty list

   // Delete the node at the end of this list
   public T removeLast( )
   {
      // Detect and handle edge case
      if( isEmpty() )                         // Edge case 1: empty list
      { // empty list can't remove anything
         throw new NoSuchElementException();
      }
      if( first.next == null )             // Edge case 2: list has 1 elem
      {
         Node<T> ret = first;   // Save for return
         first = null;          // Unlink by updating first
         return ret.item;
      }
      // General case  (take care of edge cases later)
      ... code omitted for brevity... updates previous.next
   }

DEMO: demo/11-linked-list/03-insert+remove-end/Demo.java + GenericLinkedList.java

Repeated advise...

  • Important note:

    • There are many kinds of linked lists
      (We have only been working with one kind !)

    • There are many different operations on a linked list

      • It's futile to memorize the different algorithms

  • There is a common principle in all the algorithms:

    • You must know what result you want to achieve

    • Determine the links that you need to modify to achieve the result

    • To modify the proper links:

      • Traverse the linked list to the proper node that contain the link

      • Modify the link

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(), removeFirst(), addLast() and removeLast()

  • We will study the getFirst(), getLast() and get() methods next