CS 46B - Lecture 17

Cover page image

Pre-class reading

Doubly-Linked List

Removing at Head

Singly-Linked:

public class LinkedList
{
   . . .
   public Object removeFirst()
   {
      if (first == null) { throw new NoSuchElementException(); }
      Object element = first.data;
      first = first.next; 
      return element;
   }
   . . .
}

Lecture 17 Clicker Question 1

What do we need to do to make this method work for doubly-linked lists?

  1. Nothing—it will work correctly for doubly-linked lists as well
  2. Update the previous reference of the initial node after removal
  3. Update the last reference of the LinkedList if the last element was removed
  4. Something else

Removing at Head

public class LinkedList
{
   . . .
   public Object removeFirst()
   {
      if (first == null) { throw new NoSuchElementException(); }
      Object element = first.data;
      first = first.next; 
      if (first == null) { last = null; } // List is now empty
      else { first.previous = null; }      return element;
   }
   . . .
}

Adding at Head

Singly-linked:

public void addFirst(Object element)
{
   Node newNode = new Node(); 
   newNode.data = element;
   newNode.next = first; 
   first = newNode; 
}

Lecture 17 Clicker Question 2

What do we need to do to make this method work for doubly-linked lists?

  1. Nothing—it will work correctly for doubly-linked lists as well
  2. Update the previous reference of the second node
  3. Update the last reference of the LinkedList if the last element was inserted
  4. Both 2 and 3

Adding at Head

public void addFirst(Object element)
{
   Node newNode = new Node(); 
   newNode.data = element;
   newNode.next = first; 
   if (first == null) { last = newNode; }
   else { first.previous = newNode; }
   first = newNode; 
}

Adding at Tail (New)

public void addLast(Object element)
{
   Node newNode = new Node();
   newNode.data = element;   
   newNode.previous = last;
   if (last == null) { first = newNode; }
   else { last.next = newNode; }
   last = newNode;
}

Bidirectional Iterator

Stateful Remove

Moving Backwards

public Object previous()
{
   if (!hasPrevious()) { throw new NoSuchElementException(); }
   isAfterNext = false;
   isAfterPrevious = true;
   Object result = position.data;
   position = position.previous;
   return result;
}

remove

remove

Testing the Implementation

Helper method for checking list contents

public static void check(String expected, LinkedList actual)
{
   int n = expected.length();
   if (n > 0)
   {
      // Check first and last reference       
      assertEquals(expected.substring(0, 1), actual.getFirst());
      assertEquals(expected.substring(n - 1), actual.getLast());

      // Check next references
      ListIterator iter = actual.listIterator();
      for (int i = 0; i < n; i++)
      {
         assertEquals(true, iter.hasNext());
         assertEquals(expected.substring(i, i + 1), iter.next());
      }
      assertEquals(false, iter.hasNext());

      // Check previous references
      for (int i = n - 1 ; i >= 0; i--)
      {
         assertEquals(true, iter.hasPrevious());
         assertEquals(expected.substring(i, i + 1), iter.previous());
      }
      assertEquals(false, iter.hasPrevious());
   }
   else
   {
      // Check that first and last are null
      try
      {
         actual.getFirst();
         throw new IllegalStateException("first not null");
      }
      catch (NoSuchElementException ex) 
      {
      }

      try
      {
         actual.getLast();
         throw new IllegalStateException("last not null");
      }
      catch (NoSuchElementException ex)
      {
      }                
   }
}