/* * File: ZHOneWayLinkedStructure.java */ package zhstructures; import java.util.Iterator; import java.util.NoSuchElementException; /** * Abstract class that provides a node structure for one-way linked * implementations of linear collections. The individual objects of this class * are traditionally referred to as "nodes," but we will use the term * "structure component" to refer to them in these documentation comments.
* * Classes implementing this interface will typically use this class in one of * two ways. A class may extend this class, passing its own class name as the * StructureType parameter. In this case, the implementing class should only * call constructors of this class from within its own constructors and not * from its other methods. This way of using the ZHOneWayLinkedStructure will * probably most often be used for a situation in which the implementing class * needs a single reference to a fixed starting node. A typical declaration of * this type might be:
* * public class Foo\ * extends ZHOneWayLinkedStructure\\> ...
* * The second way to use this class occurs when the implementing class needs * one or more instance variable references to parts of the structure. In this * case, the implementing class declares a protected inner class that extends * this class with the inner class name passed as the StructureType generic * parameter; the outer class also declares one or more instance variables of * the inner class type. The inner class need only implement constructors that * match the constructors of this class, but it may of course implement any * additional methods that will be useful in traversing the structure. If the * implementing class is not a member of the zhstructures package, it will be * necessary to add appropriate accessor methods to the inner class, typically * getElement(), getNext() and getState().
* * Structure components are either empty or not. In an empty structure * component, the element and next instance variables are irrelevant and should * be set to null (or left uninitialized) to facilitate garbage collection. If * a structure component is not empty, both its element and next variables must * be initialized with appropriate objects. Following this convention, there is * always exactly one empty component at the end of every structure, and all * other components in the structure are non-empty. * * @param ElementType the type of data elements contained in this structure * @param StructureType a class extending this class that is to be used in a particular * collection, typically the class extending this class * * @author J. Andrew Holey * @version August 10, 2008, documentation revised January 15, 2009 */ public abstract class ZHOneWayLinkedStructure > implements ZHCollection { /** * The data element associated with this component. * This variable should be null in an empty component and should refer to * an object in a non-empty component (unless null elements are allowed in * the collection). */ protected ElementType element; /** * The component that follows this one in this structure. * This variable should be null in an empty component and should refer to * another structure component (possibly empty) in a non-empty component. */ protected StructureType next; /** * The state of this component: either ZHComponentState.EMPTY or * ZHComponentState.NOT_EMPTY */ protected ZHComponentState state; /** * Creates a new empty structure. */ public ZHOneWayLinkedStructure() { this.state = ZHComponentState.EMPTY; /* * The remaining instance variables (element & next) are irrelevant * in an empty structure and so need not be initialized in this * constructor. */ } /** * Creates a new non-empty structure component with the specified element * and next structure component. * * @param element the data element associated with this structure component * @param next the next component in this structure, which should generally * be an actual component rather than null */ public ZHOneWayLinkedStructure(ElementType element, StructureType next) { this.element = element; this.next = next; this.state = ZHComponentState.NOT_EMPTY; } /* (non-Javadoc) * @see zhstructures.ZHCollection#contains(java.lang.Object) */ public boolean contains(ElementType element) { switch (this.state) { case EMPTY: return false; case NOT_EMPTY: return (element.equals(this.element) || this.next.contains(element)); default: throw new IllegalStateException(); } } /* (non-Javadoc) * @see zhstructures.ZHCollection#isEmpty() */ public boolean isEmpty() { switch (this.state) { case EMPTY: return true; case NOT_EMPTY: return false; default: throw new IllegalStateException(); } } /* (non-Javadoc) * @see zhstructures.ZHCollection#iterator() */ @SuppressWarnings("unchecked") public Iterator iterator() { return new InternalIterator((StructureType) this); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { // TODO Auto-generated method stub if (this == obj) { return true; } try { StructureType otherStructure = (StructureType) obj; return (this.element.equals(otherStructure.element) && this.next.equals(otherStructure.next)); } catch (ClassCastException cce) { return false; } } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int hashCode = 1; for (ElementType element : this) { hashCode = 31 * hashCode + element.hashCode(); } return hashCode; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { if (this.isEmpty()) return "[]"; StringBuilder result = new StringBuilder(); return this.toString(this, result); } private String toString(ZHOneWayLinkedStructure component, StringBuilder result) { result.append(component.element.toString()); if (component.next.isEmpty()) { return result.toString(); } else { result.append(", "); return this.toString(component.next, result); } } /** * Iterator class for the structure. * This iterator does not support the remove operation. */ protected class InternalIterator implements Iterator { private StructureType currentStructure; /** * Creates a new iterator starting at the specified component. * * @param startComponent the node at which to start iteration */ public InternalIterator(StructureType startComponent) { currentStructure = startComponent; } /* (non-Javadoc) * @see java.util.Iterator#hasNext() */ public boolean hasNext() { switch (currentStructure.state) { case EMPTY: return false; case NOT_EMPTY: return true; } throw new IllegalStateException(); } /* (non-Javadoc) * @see java.util.Iterator#next() */ public ElementType next() { switch (currentStructure.state) { case EMPTY: throw new NoSuchElementException(); case NOT_EMPTY: ElementType result = currentStructure.element; currentStructure = currentStructure.next; return result; } throw new IllegalStateException(); } /* (non-Javadoc) * @see java.util.Iterator#remove() */ public void remove() { throw new UnsupportedOperationException(); } } }