Files

498 lines
13 KiB
Java
Raw Permalink Normal View History

2026-01-23 17:03:45 +08:00
/*
* 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.<p>
* The second improvement lies in the reusable iterators. Now, if an iterator was constructed, it can be reused over and over using its
* <tt>reset()</tt> 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 <u>only</u> 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 <i>this</i>.
*
* @return the size as int
*/
public int size () {
return this.size;
}//end method size
/**
* Returns <tt>true</tt>, if <i>this</i> is empty.
*
* @return <tt>true</tt>, if empty; false otherwise
*/
public boolean isEmpty() {
if (head.next == null) return true;
else return false;
}//end method isEmpty
/**
* Adds an object to <i>this</i>.
* 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 <i>this</i>.
* The new element will be sorted correctly in the list using the comparator of <i>this</i>.
* 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 <i>this</i>.
*
* @return the first object
*/
public Object getFirst() {
return head.next.value;
}//end method getFirst
/**
* Returns the last element of <i>this</i>.
*
* @return the last object
*/
public Object getLast() {
return last.next.value;
}//end method getLast
/**
* Adds to <i>this</i> all elements of <tt>pll</tt>.
* 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 <i>this</i>.
* The iterator starts at <tt>index</tt>.
*
* @param index the start position for the iterator
* @return the iterator for <i>this</i>
*/
public ProListIterator listIterator (int index) {
return new ProListIterator(this,index);
}//end method listIterator
/**
* Adds a new entry directly before <tt>e</tt>.
*
* @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 <i>this</i>.
* 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 <tt>idx</tt> from the list.
*
* @param idx the object at that position shall be removed
* @throws IndexOutOfBoundsException if <tt>idx</tt> is greater than <tt>this.size</tt> 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 <tt>idx</tt>.
*
* @param idx the index of the object
* @throws IndexOutOfBoundsException if <tt>idx</tt> is greater than <tt>this.size</tt> 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 <tt>idx</tt>.
*
* @param idx the index where o shall be added
* @param o the new object
* @throws IndexOutOfBoundsException if <tt>idx</tt> is greater than <tt>this.size</tt> 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 <i>this</i> 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 <i>this</i>.
*
* @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