import java.util.Comparator;
//============================================================================//
/**
* Implementation of homework 11.
*
* @author Cheng Jade
* @assignment ICS211 Homework TA11
* @date Apr 15, 2010
* @bugs None
*/
public class ChengJade11 {
/**
* The main entry point of the program.
*
* @param args
* The command line arguments (not used).
*/
public static void main(final String[] args) {
// Test the sort on a list with no items.
final LinkedList<String> list = new LinkedList<String>();
final StringComparator comparator = new StringComparator();
list.bubbleSort(comparator);
System.out.println("A sorted, empty list:\n\n" + list);
// Test the sort on a list with one item.
list.add("Fiji");
list.bubbleSort(comparator);
System.out.println("A sorted, one-item list:\n\n" + list);
// Test the sort on a list with two item.
list.add("Egypt");
list.bubbleSort(comparator);
System.out.println("A sorted, two-item list:\n\n" + list);
// Test the sort on a few more items including a null item (the class
// supports null values).
list.add("Brazil");
list.add("Hungary");
list.add("Denmark");
list.add("Germany");
list.add("Zimbabwe");
list.add("Korea");
list.add("Lao");
list.add("Russia");
list.add("Malaysia");
list.add("Philippines");
list.add("Yemen");
list.add("Viet Nam");
list.add("Italy");
list.add("Japan");
list.add("New Zealand");
list.add("Argentina");
list.add("China");
list.add("Qatar");
list.add("USA");
list.add("Western Sahara");
list.add("Oman");
list.add("Singapore");
list.add("Thailand");
System.out.println("An unsorted list with several items:\n\n" + list);
// Sort the list using a StringComparator, and display it again.
list.bubbleSort(comparator);
System.out.println("A sorted list with several items:\n\n" + list);
// Test the sort on a list with duplicated item.
final LinkedList<String> duplicatedList = new LinkedList<String>();
duplicatedList.add("thailand");
duplicatedList.add("Thailand");
duplicatedList.add("Denmark");
duplicatedList.add("denmark");
System.out.println("An unsorted list with duplicated items:\n\n" + duplicatedList);
duplicatedList.bubbleSort(comparator);
System.out.println("A sorted list with duplicated items:\n\n" + duplicatedList);
System.exit(0);
}
}
/**
* A comparator class that compares two strings ignoring case.
*/
class StringComparator implements Comparator<String> {
/**
* Compares two strings ignoring case. Two null strings are considered
* equal, a non-null string is considered greater than a null string, and
* two non-null strings are compared using compareToIgnoreCase from the
* String class.
*
* @param s1
* The first string.
* @param s2
* The second string.
* @return A value compatible with compareToIgnoreCase from the String
* class.
*/
public int compare(final String s1, final String s2) {
if (s1 == null)
return s2 == null ? 0 : -1;
return s2 == null ? 1 : s1.compareToIgnoreCase(s2);
}
}
/**
* An exception thrown when an invalid position is passed to the remove method
* of the LinkedList class.
*/
@SuppressWarnings("serial")
class BadItemCountException extends RuntimeException {
/**
* Initializes a new instance of the class.
*
* @param message
* The message describing the failure.
*/
public BadItemCountException(final String message) {
super(message);
}
}
// ============================================================================//
/*
* a generic list implemented using a linked list of nodes
*
* @author Biagioni, Edoardo
*
* @assignment lecture 9 and assignment 10
*
* @date February 11, 2008
*
* @inspiration William Albritton's GenericLinkedList.java
* http://www2.hawaii.edu
* /~walbritt/ics211/linkedListGeneric/GenericLinkedList.java
*/
class LinkedList<T> {
/*
* only need to store a single pointer to the node at the head of the list.
* The pointer is null if the list is empty. Also record the size of the
* list.
*/
protected Node<T> head;
/* invariant: size is the number of nodes in the list pointed to by head */
protected int size;
/* no-arguments default constructor creates an empty list */
public LinkedList() {
this.head = null; // start with an empty list
this.size = 0;
}
/* accessor method */
public int size() {
return this.size;
}
/*
* @param value to add to the end of the list
*/
public void add(final T value) {
this.head = this.addAtEnd(this.head, value);
this.size++;
}
// ==========================================================================//
/**
* Sorts the list using the bubble sort algorithm.
*
* @param comparator
* A generic Comparator for T.
* @throws NullPointerException
* if the comparator is null.
*/
public void bubbleSort(final Comparator<T> comparator) {
// The comparator is required by the method.
if (comparator == null)
throw new NullPointerException("c");
// Do nothing if there are fewer than two items in the collection.
if (this.head == null || this.head.getNext() == null)
return;
// Perform the bubble sort for a singly-linked list.
boolean swapped;
do {
swapped = false;
for (Node<T> i = this.head; i.getNext() != null; i = i.getNext())
if (comparator.compare(i.getValue(), i.getNext().getValue()) > 0)
swapped = this.swap(i, i.getNext());
} while (swapped);
// If this were a doubly-linked list, the following algorithm could be
// used.
// It is slightly simpler (I think).
//
// for (BinaryNode<T> i = head; i != null; i = i.next)
// for (BinaryNode<T> j = tail; j != i; j = j.previous)
// if (comparator.compare(j.value, i.value) < 0)
// swap(i, j);
}
/**
* Swaps two nodes by switching the nodes' values.
*
* @param n1
* the first node to swap.
* @param n2
* the second node to swap.
* @return This method always returns true.
*/
private boolean swap(final Node<T> n1, final Node<T> n2) {
assert n1 != null;
assert n2 != null;
final T temp = n1.getValue();
n1.setValue(n2.getValue());
n2.setValue(temp);
return true;
}
// ==========================================================================//
/*
* @param node of the list to which the value should be added @param value
* to add to the end of the list
*/
private Node<T> addAtEnd(final Node<T> node, final T value) {
if (node == null) { // special case
return new Node<T>(value, null);
} else if (node.getNext() == null) { // other special case
node.setNext(new Node<T>(value, null));
} else {
this.addAtEnd(node.getNext(), value);
}
return node;
}
/*
* iterative implementation of the same method
*
* @param value to add to the end of the list
*/
public void add2(final T value) {
if (this.head == null) {
this.head = new Node<T>(value, null);
} else {
Node<T> node = this.head; // guaranteed not to be null initially
while (node.getNext() != null) {
node = node.getNext(); // guaranteed not to be null here
}
// now, node.getNext() is guaranteed to be null
// similar to the second special case in addAtEnd
node.setNext(new Node<T>(value, null));
}
this.size++;
}
/*
* @param position of item to be removed
*
* @throws BadItemCountException if this is not a valid position position is
* 1-based, so position = 1 removes the head
*/
public void remove(final int position) throws BadItemCountException {
if ((position < 1) || (position > this.size)) {
throw new BadItemCountException("invalid position " + position
+ ", only 1.." + this.size + " available");
}
if (position == 1) {
this.head = this.head.getNext();
} else {
Node<T> node = this.head;
for (int i = 2; i < position; i++) {
node = node.getNext();
}
// set this node's "next" pointer to refer to the
// node that is after the next
node.setNext(node.getNext().getNext());
}
this.size--; // one less item
}
/*
* convert the list to a printable string
*
* @return a string representing the stack
*/
@Override
public String toString() {
return this.toString(this.head);
}
private String toString(final Node<T> node) {
if (node == null) {
return "";
} else {
return node.getValue() + "\n" + this.toString(node.getNext());
}
}
/*
* unit test -- test all the methods in this class
*
* @param ignored
*/
public static void main(final String[] args) {
/* create two empty lists, make sure they print out correctly */
final LinkedList<String> list1 = new LinkedList<String>();
final LinkedList<String> list2 = new LinkedList<String>();
System.out.println("list1 = '" + list1 + "', list2 = '" + list2 + "'");
System.out.println("list1.size() = " + list1.size() + ", list2.size() = " + list2.size());
/* insert some items, keep checking */
list1.add("hello");
list1.add("world");
list2.add("foo");
list2.add("bar");
list2.add("baz");
System.out.println("list1 = '" + list1 + "', list2 = '" + list2 + "'");
System.out.println("list1.size() = " + list1.size() + ", list2.size() = " + list2.size());
/* remove an item at an invalid position */
boolean caught = false;
try {
list2.remove(4);
} catch (final BadItemCountException e) {
caught = true;
}
if (!caught) {
System.out.println("error: no exception for invalid remove");
System.out.println("list1 = '" + list1 + "', list2 = '" + list2 + "'");
}
System.out.println("list1 = '" + list1 + "', list2 = '" + list2 + "'");
/* remove some items at valid positions */
try {
list1.remove(1);
System.out.println("list1 = '" + list1 + "', list2 = '" + list2 + "'");
list2.remove(2);
System.out.println("list1 = '" + list1 + "', list2 = '" + list2 + "'");
list2.remove(2);
System.out.println("list1 = '" + list1 + "', list2 = '" + list2 + "'");
} catch (final Exception e) {
System.out.println("caught unexpected exception " + e + ", list1 = '" + list1 + ", list2 = " + list2);
}
System.out.println("list1.size() = " + list1.size() + ", list2.size() = " + list2.size());
}
}
/*
* a class for nodes that store arbitrary objects
*
* @author Biagioni, Edoardo
*
* @assignment lecture 9
*
* @date February 11, 2008
*/
class Node<T> {
/*
* two fields, the first to store the item itself, the second is a pointer
* to the next node in the linked list. If there is no next node, the
* pointer is null.
*/
private T item;
private Node<T> nextNode;
/*
* constructor:
*
* @param value, the value for the node
*
* @param next, the next node in the linked list
*/
public Node(final T value, final Node<T> next) {
this.item = value;
this.nextNode = next;
}
/* accessor methods */
public T getValue() {
return this.item;
}
public Node<T> getNext() {
return this.nextNode;
}
/* mutator methods */
public void setNext(final Node<T> newNext) {
this.nextNode = newNext;
}
public void setValue(final T value) {
this.item = value;
}
}