CS 136 - Lecture 10

  1. Extending Classes: Inheritance
  2. Other linked list representations
    1. Circularly-linked lists

Extending Classes: Inheritance

If class A extends B then A automatically gets all methods and instance variables from B.

A can also add new methods or redefine the "inherited" methods.

When redefine methods, can call original version from superclass:

   super.meth(a,b)
With constructors, simply write
   super(...)
to first execute the constructor of the superclass.

See examples with Position and RowOrderPosn as well as CurDoublyLinkedList as extension of DoublyLinkedList.


Linked List Implementations (cont'd.)


Circularly Linked Lists

Circularly linked list. Head always found as tail.next()!

public class CircularList implements List {

   protected SinglyLinkedListElement tail;
   protected int count;

   public CircularList()
   // pre: constructs a new circular list
   {
      tail = null;
      count = 0;
   }

   public void add(Object value)
   // post: adds value to beginning of list.
   {
      addToHead(value);
   }

   public void addToHead(Object value)
   // pre: value non-null
   // post: adds element to head of list
   {
      SinglyLinkedListElement temp =
          new SinglyLinkedListElement(value);
      if (tail == null) {
          tail = temp;
          tail.setNext(tail);
      }
      else {
          temp.setNext(tail.next());
          tail.setNext(temp);
      }
      count++;
   }

   public void addToTail(Object value)
   // pre: value non-null
   // post: adds element to tail of list
   {
      addToHead(value);
      tail = tail.next();      // moves new from head to tail
   }

   public Object peek()
   // pre: !isEmpty()
   // post: returns value at head of list
   {
      return tail.next().value();
   }

   public Object tailPeek()
   // pre: !isEmpty()
   // post: returns value at tail of list
   {
      return tail.value();
   }

   public Object removeFromHead()
   // pre: !isEmpty()
   // post: returns and removes value from head of list
   {
      SinglyLinkedListElement temp = tail.next();  // ie. the head of the list

      if (tail == tail.next())                     // 1 elt in list
          tail = null;
      else {
          tail.setNext(temp.next());
          temp.setNext(null);             // helps clean things up
      }              // temp is free
      count--;
      return temp.value();
   }

   public Object removeFromTail()
   // pre: !isEmpty()
   // post: returns and removes value from tail of list
   {
      Assert.pre(!isEmpty(),"The list is not empty.");
      SinglyLinkedListElement finger = tail;
      while (finger.next() != tail)
          finger = finger.next();
      // finger now points to second-to-last value
      SinglyLinkedListElement temp = tail;
      if (finger == tail)
          tail = null;
      else {
          finger.setNext(tail.next());
          tail = finger;
      }
      count--;
      return temp.value();
   }

   public boolean contains(Object value)
   // pre: value != null
   // post: returns true if list contains value, else false
   {
      if (tail == null) return false;

      SinglyLinkedListElement finger;
      finger = tail.next();
      while ((finger != tail) && (!finger.value().equals(value)))
          finger = finger.next();
      return finger.value().equals(value);
   }

   public Object remove(Object value)
   // pre: value != null
   // post: remove & returns element equal to value, or null
   {
      if (tail == null) return null;

      SinglyLinkedListElement finger = tail.next();
      SinglyLinkedListElement previous = tail;
      int compares;
      for (compares = 0;
           (compares < count) && (!finger.value().equals(value));
           compares++)
      {
          previous = finger;
          finger = finger.next();
      }
      if (finger.value().equals(value)) {
          // an example of the pigeon-hole principle
          if (tail == tail.next())
              tail = null;
          else {
              if (finger == tail)
                  tail = previous;
              previous.setNext(previous.next().next());
          }
          // finger value free
          finger.setNext(null)       // to keep things disconnected
          count--;                   // fewer elements
          return finger.value();
      }
      else
      return null;
   }

   public int size()
   // post: returns number of elements in list
   {
      return count;
   }

   public boolean isEmpty()
   // post: returns true if no elements in list
   {
      return tail == null;
   }

   public void clear()
   // post: removes all elements from list.
   {
      count = 0;
      tail = null;
   }
}

Why not put references in both directions!?!