/* * ProLinkedList.java 2005-05-11 * * Dirk Ansorge, FernUniversitaet Hagen * */ package twodsack.util.collection; import twodsack.set.*; import twodsack.setelement.*; import twodsack.util.collectiontype.*; import twodsack.util.iterator.*; import java.util.*; /** * The implementation of a ProLinkedList class was necessary to remove some drawbacks of Sun's {@link java.util.LinkedList}. * First, it provides the {@link #addAll(ProLinkedList)} method, * that concats two ProLinkedLists without copying any objects. This is possible, because the elements of such lists are connected twice: they * have one pointer to their successor and one pointer to their predecessor. Additionally, for a list one pointer points to the head of the list * and another pointer points to the last element. Then, a concatenation of two lists is done by simple redirecting some pointers. However, * you must be aware that the original lists cannot be used anymore.
* The second improvement lies in the reusable iterators. Now, if an iterator was constructed, it can be reused over and over using its * reset() method. This saves a lot of time and memory. */ public class ProLinkedList implements Cloneable { /* * fields */ /** * The size of the list. */ public int size; /** * This entry points to the first list entry. */ public Entry head; //points to the first Entry /** * This entry points to the last list entry. */ public Entry last; //points to the last Entry /** * A counter for being able to check concurrent modifications. */ public int modCount; private Comparator comparator; //is used for method remove(object) /** * Points to the entry that was added at last. */ public Entry lastAdded; //points to the Entry that was added the last time /* * constructors */ /** * The empty constructor. */ public ProLinkedList() { modCount = 0; size = 0; head = new Entry(null); last = new Entry(null); comparator = null; } /** * Constructs a new instance using a comparator. * The comparator is only used when calling the {@link #remove(Object)} method. * * @param c the comparator c */ public ProLinkedList(Comparator c) { modCount = 0; size = 0; head = new Entry(null); last = new Entry(null); comparator = c; } /** * Constructs a new instance from the passed MultiSet. * The passed comparator is used for the construction of the new list. * * @param c the new comparator * @param ems the MultiSet */ public ProLinkedList(MultiSet ems, Comparator c) { comparator = c; modCount = 0; size = 0; head = new Entry(null); last = new Entry(null); Iterator it = ems.iterator(); Object actElem; while (it.hasNext()) { actElem = ((MultiSetEntry)it.next()).value; this.add(actElem); }//while it } /* * methods */ /** * Returns the size of this. * * @return the size as int */ public int size () { return this.size; }//end method size /** * Returns true, if this is empty. * * @return true, if empty; false otherwise */ public boolean isEmpty() { if (head.next == null) return true; else return false; }//end method isEmpty /** * Adds an object to this. * The new element will be the last element of this. * * @param o the new element */ public void add (Object o) { Entry newEntry = new Entry(o); lastAdded = newEntry; if (head.next == null) { head.next = newEntry; last.next = newEntry; }//if else { last.next.next = newEntry; newEntry.prev = last.next; last.next = newEntry; }//else this.size++; this.modCount++; }//end method add /** * Adds an object to this. * The new element will be sorted correctly in the list using the comparator of this. * If no comparator is specified, an exception is thrown. * * @param o the new element * @return the position of the list where the new element was added; first position is 0 * @throws ComparatorNotDefinedException if no comparator is defined */ public int addSorted (Object o) { int pos = -1; if (this.comparator == null) throw new ComparatorNotDefinedException("Comparator is needed for this operation. Use constructor ProLinkedList(Comparator)."); Entry newEntry = new Entry(o); lastAdded = newEntry; if (head.next == null) { head.next = newEntry; last.next = newEntry; pos = 0; }//if else if (comparator.compare(o,head.next.value) == -1) { //if new entry is smaller than first entry newEntry.next = head.next; newEntry.prev = null; head.next.prev = newEntry; head.next = newEntry; pos = 0; }//if //if new entry is greater than last entry else if (comparator.compare(o,last.next.value) == 1) { newEntry.prev = last.next; newEntry.next = null; last.next.next = newEntry; last.next = newEntry; pos = this.size; }//if else { //traverse list using comparator Entry nextEntry = head.next; pos = 0; while (comparator.compare(o,nextEntry.value) >= 0) { nextEntry = nextEntry.next; pos++; }//while newEntry.next = nextEntry; newEntry.prev = nextEntry.prev; nextEntry.prev.next = newEntry; nextEntry.prev = newEntry; }//else this.size++; this.modCount++; return pos; }//end method addSorted /** * Returns the first element of this. * * @return the first object */ public Object getFirst() { return head.next.value; }//end method getFirst /** * Returns the last element of this. * * @return the last object */ public Object getLast() { return last.next.value; }//end method getLast /** * Adds to this all elements of pll. * The resulting list is a concatenation of both lists. * * @param pll the second list */ public void addAll (ProLinkedList pll) { if (this.size == 0) { this.head.next = pll.head.next; this.head.prev = pll.head.prev; this.last.next = pll.last.next; this.last.prev = pll.last.prev; this.modCount = pll.modCount; this.size = pll.size; }//if else { if (pll.size > 0) { this.last.next.next = pll.head.next; pll.head.next.prev = this.last.next; this.last.next = pll.last.next; this.size = this.size+pll.size; this.modCount = this.modCount+pll.size; }//if }//else }//end method addAll /** * Returns a new iterator for this. * The iterator starts at index. * * @param index the start position for the iterator * @return the iterator for this */ public ProListIterator listIterator (int index) { return new ProListIterator(this,index); }//end method listIterator /** * Adds a new entry directly before e. * * @param o the object that shall be added * @param e the entry that shall have the position directly after o in the result list */ public void addBeforeAct(Object o, Entry e) { Entry newEntry = new Entry(o); lastAdded = newEntry; modCount++; if (!(e == null)) { newEntry.next = e; newEntry.prev = e.prev; e.prev = newEntry; if (newEntry.prev != null) newEntry.prev.next = newEntry; else head.next = newEntry; } else { if (size > 0) { newEntry.next = null; newEntry.prev = last.next; last.next.next = newEntry; last.next = newEntry; } else { newEntry.next = null; newEntry.prev = null; head.next = newEntry; last.next = newEntry; }//else }//else size++; }//end method addBefore /** * Removes an object from this. * Note: This method doesn't work, if the list was constructed without a comparator. * * @param o the object that shall be removed * @throws ComparatorNotDefinedException if the list was not constructed using a comparator */ public void remove (Object o) throws ComparatorNotDefinedException { if (this.comparator == null) throw new ComparatorNotDefinedException("Comparator is needed for this operation. Use constructor ProLinkedList(Comparator)."); if (!(o == null)) { //if (o.equals(head.next.value)) { if (this.comparator.compare(o,head.next.value) == 0) { if (size == 1) { head.next = null; last.next = null; }//if else { head.next.next.prev = null; head.next = head.next.next; }//else }//if else if (this.comparator.compare(o,last.next.value) == 0) { last.next = last.next.prev; last.next.next = null; }//else if else { for (Entry e = head.next; e != null; e = e.next) { //if (o.equals(e.value)) { if (this.comparator.compare(o,e.value) == 0) { if (e.next != null) { e.prev.next = e.next; e.next.prev = e.prev; }//if else { e.prev.next = null; e.prev = null; }//else }//if }//for }//else size--; modCount++; }//if }//end method remove /** * Removes the object at position idx from the list. * * @param idx the object at that position shall be removed * @throws IndexOutOfBoundsException if idx is greater than this.size or less than 0 */ public void remove (int idx) { if (idx >= size || idx < 0) throw new IndexOutOfBoundsException("Index: "+idx+", Size: "+size); else { if (idx == 0) { if (head.next.next != null) { head.next.next.prev = null; head.next = head.next.next; }//if else { head.next = null; last.next = null; }//else }//if else { Entry actEntry = head.next; for (int count = 0; count < idx; count++) actEntry = actEntry.next; if (actEntry.next != null) { actEntry.prev.next = actEntry.next; actEntry.next.prev = actEntry.prev; }//if else { last.next = actEntry.prev; actEntry.prev.next = null; actEntry.prev = null; }//else }//else modCount++; size--; }//else }//end method remove /** * Returns the objects which at position idx. * * @param idx the index of the object * @throws IndexOutOfBoundsException if idx is greater than this.size or less than 0 */ public Object get (int idx) throws IndexOutOfBoundsException { Entry actEntry = head.next; if (idx > size || idx < 0) throw new IndexOutOfBoundsException("Index: "+idx+", Size: "+size); else { for (int count = 0; count < idx; count++) actEntry = actEntry.next; }//else return actEntry.value; }//end method get /** * Adds an object at position idx. * * @param idx the index where o shall be added * @param o the new object * @throws IndexOutOfBoundsException if idx is greater than this.size or less than 0 */ public void add (int idx, Object o) throws IndexOutOfBoundsException { if (idx > size || idx < 0) throw new IndexOutOfBoundsException("Index: "+idx+", Size: "+size); Entry actEntry = head.next; for (int count = 0; count < idx; count++) actEntry = actEntry.next; Entry newEntry = new Entry(o); if (actEntry.prev == null) { newEntry.next = head.next; head.next.prev = newEntry; head.next = newEntry; }//if else { newEntry.next = actEntry; newEntry.prev = actEntry.prev; actEntry.prev.next = newEntry; actEntry.prev = newEntry; }//else modCount++; size++; lastAdded = newEntry; }//end method add /** * Removes all objects from the list. */ public void clear() { head.next = null; last.next = null; modCount++; size = 0; }//end method clear /** * Writes all object of this to an array. * * @return the objects of this stored in an array */ public Object[] toArray() { Object[] result = new Object[size]; Entry actEntry = head.next; ProListIterator it = this.listIterator(0); while (it.hasNext()) result[it.nextIndex()] = it.next(); return result; }//end method toArray /** * Prints the objects of the list to standard output. */ public void print() { if (this.isEmpty()) System.out.println("List is empty."); ProListIterator it = this.listIterator(0); int count = 0; while (it.hasNext()) { System.out.println("["+count+"]: "+it.next()); count++; }//while }//end method print /** * Returns a clone of this. * * @return the clone as Object */ public Object clone () { Object clone; try { clone = super.clone(); } catch(Exception e) { throw new InternalError("ProLinkedList: cloning not supported."); }//catch return clone; }//end method clone }//end method ProLinkedList