Data Structures, Algorithms, & Applications in Java
Chapter 11, Exercise 31
The code for the new class is given below.
The tail node has been used to
simplify the conditions in the while
loops. As a result, the new code is expected to run faster than
the code of SortedChain.
public class SortedChainWithTail implements Dictionary
{
// top-level nested class
protected static class SortedChainNode
{
// data members
protected Comparable key;
protected Object element;
protected SortedChainNode next;
// constructors
protected SortedChainNode() {}
protected SortedChainNode(Object theKey, Object theElement)
{
key = (Comparable) theKey;
element = theElement;
}
protected SortedChainNode(Object theKey, Object theElement,
SortedChainNode theNext)
{
key = (Comparable) theKey;
element = theElement;
next = theNext;
}
}
// data members of SortedChainWithTail
protected SortedChainNode firstNode;
protected SortedChainNode tailNode;
protected int size;
// constructors
/** create an empty sorted chain */
public SortedChainWithTail(int initialCapacity)
{
// create the tail node
tailNode = new SortedChainNode();
firstNode = tailNode;
// the default initial value of size is 0
}
public SortedChainWithTail()
{this(0);}
// methods
/** @return true iff the chain is empty */
public boolean isEmpty()
{return size == 0;}
/** @return current number of elements in list */
public int size()
{return size;}
/** @return element with specified key
* @return null if there is no matching element */
public Object get(Object theKey)
{
// put theKey into tailNode
tailNode.key = (Comparable) theKey;
SortedChainNode currentNode = firstNode;
// search for match with theKey
while (currentNode.key.compareTo(theKey) < 0)
currentNode = currentNode.next;
// verify match
if (currentNode != tailNode && currentNode.key.equals(theKey))
// yes, found match
return currentNode.element;
// no match
return null;
}
/** insert an element with the specified key
* overwrite old element if there is already an
* element with the given key
* @return old element (if any) with key = theKey */
public Object put(Object theKey, Object theElement)
{
// first put theKey into the tail node
tailNode.key = (Comparable) theKey;
SortedChainNode currentNode = firstNode;
SortedChainNode trailNode = null; // node left of currentNode
// move currentNode so that theElement can be inserted just before
// currentNode
while (currentNode.key.compareTo(theKey) < 0)
{
trailNode = currentNode;
currentNode = currentNode.next;
}
// check if there is a matching element
if (currentNode != tailNode && currentNode.key.equals(theKey))
{// replace old element
Object elementToReturn = currentNode.element;
currentNode.element = theElement;
return elementToReturn;
}
// insert just before currentNode
SortedChainNode p = new SortedChainNode(theKey, theElement,
currentNode);
if (currentNode == firstNode)
// p is new first node
firstNode = p;
else
// p is not new first node, set link from node to its left
trailNode.next = p;
size++;
return null;
}
/** @return matching element and remove it
* @return null if no matching element */
public Object remove(Object theKey)
{
// first put theKey into the tail node
tailNode.key = (Comparable) theKey;
SortedChainNode currentNode = firstNode;
SortedChainNode trailNode = null; // node left of currentNode
// move currentNode to node with natching element (if any)
while (currentNode.key.compareTo(theKey) < 0)
{
trailNode = currentNode;
currentNode = currentNode.next;
}
// check if there is a matching element
if (currentNode != tailNode && currentNode.key.equals(theKey))
{// there is a matching element, save in e and remove from chain
Object e = currentNode.element;
if (currentNode == firstNode)
// remove first node
firstNode = firstNode.next;
else
// remove interior node
trailNode.next = currentNode.next;
size--;
return e;
}
// no matching element to remove
return null;
}
/** convert to a string */
public String toString()
{
StringBuffer s = new StringBuffer("[");
SortedChainNode currentNode = firstNode;
if (currentNode != tailNode)
{// nonempty chain
// do first element
s.append(currentNode.element.toString());
// do remaining elements
currentNode = currentNode.next;
while (currentNode != tailNode)
{
s.append(", " + currentNode.element.toString());
currentNode = currentNode.next;
}
}
s.append("]");
// create equivalent String
return new String(s);
}
/** create and return an iterator */
public Iterator iterator()
{return new SortedChainWithTailIterator();}
/** sorted chain with tail iterator */
private class SortedChainWithTailIterator implements Iterator
{
// data member
private SortedChainNode nextNode;
// constructor
public SortedChainWithTailIterator()
{nextNode = firstNode;}
// methods
/** @return true iff list has more elements */
public boolean hasNext()
{return nextNode != tailNode;}
/** @return next element in list
* @throws NoSuchElementException
* if there is no next element */
public Object next()
{
if (nextNode != tailNode)
{
Object obj = nextNode.element;
nextNode = nextNode.next;
return obj;
}
else throw new NoSuchElementException
("No next element");
}
/** unsupported method */
public void remove()
{
throw new UnsupportedOperationException
("remove not supported");
}
}
}
The test program and output are in the files
SortedChainWithTail.*.