/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.collections;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import xxl.core.comparators.ComparableComparator;
/**
* This class contains various methods for manipulating lists.
*
* <p>The documentation of the searching methods contained in this class
* includes a brief description of the implementation. Such descriptions
* should be regarded as implementation notes, rather than parts of the
* specification. Implementors should feel free to substitute other
* algorithms, as long as the specification itself is adhered to.</p>
*
* @see ComparableComparator
* @see Comparator
* @see List
*/
public class Lists {
/**
* The default constructor has private access in order to ensure
* non-instantiability.
*/
private Lists() {
// private constructor avoids instantiation
}
/**
* Searches the specified list for the first or last appearance of the
* specified object using the binary search algorithm. The list
* <b>must</b> be sorted into ascending order according to the
* specified comparator before calling this method. If it is not
* sorted, the results are undefined. If the list contains multiple
* elements equal to the specified object, the boolean value
* <code>last</code> decides whether the first or last appearance will be
* found.
*
* @param <S> the type of the elements the given lsit is able to store.
* @param <T> the type of the object to be searched for (must be a subtype
* of S).
* @param list the list to be searched.
* @param object the object to be searched for.
* @param comparator the comparator by which the list is ordered.
* @param last if false, the first appearance will be found; if true,
* the last appearance will be found.
* @return index of the search object, if it is contained in the list;
* otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.<br>
* The <i>insertion point</i> is defined as the point at which
* the object would be inserted into the list: the index of
* the first element greater than the object, or
* <code>list.size()</code>, if all elements in the list are less
* than the specified object. Note that this guarantees that
* the return value will be ≥ 0 only if the key is
* found.
* @throws ClassCastException if the list contains
* elements that are not <i>mutually comparable</i> using the
* specified comparator, or the search object is not
* <i>mutually comparable</i> with the elements of the list
* using this comparator.
*/
public static <S, T extends S> int indexOf(List<S> list, T object, Comparator<? super S> comparator, boolean last) {
return last ? lastIndexOf(list, object, comparator) : firstIndexOf(list, object, comparator);
}
/**
* Searches the specified list for the first or last appearance of the
* specified object using the binary search algorithm. The list
* <b>must</b> be sorted into ascending order according to the
* <i>natural ordering</i> of its elements before calling this method.
* If it is not sorted, the results are undefined. If the list
* contains multiple elements equal to the specified object, the
* boolean value <code>last</code> decides whether the first or last
* appearance will be found.
*
* @param <S> the type of the elements the given list is able to store.
* @param <T> the type of the object to be searched for (must be a subtype
* of S).
* @param list the list to be searched.
* @param object the object to be searched for.
* @param last if false, the first appearance will be found; if true,
* the last appearance will be found.
* @return index of the search object, if it is contained in the list;
* otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.<br>
* The <i>insertion point</i> is defined as the point at which
* the object would be inserted into the list: the index of
* the first element greater than the object, or
* <code>list.size()</code>, if all elements in the list are less
* than the specified object. Note that this guarantees that
* the return value will be ≥ 0 only if the key is
* found.
* @throws ClassCastException if the list contains
* elements that are not <i>mutually comparable</i>, or the
* search object is not <i>mutually comparable</i> with the
* elements of the list.
*/
public static <S extends Comparable<S>, T extends S> int indexOf(List<S> list, T object, boolean last) {
return indexOf(list, object, new ComparableComparator<S>(), last);
}
/**
* Searches the specified list for the first appearance of the
* specified object using the binary search algorithm. The list
* <b>must</b> be sorted into ascending order according to the
* specified comparator before calling this method. If it is not
* sorted, the results are undefined. If the list contains multiple
* elements equal to the specified object, the first appearance will
* be found.
*
* @param <S> the type of the elements the given list is able to store.
* @param <T> the type of the object to be searched for (must be a subtype
* of S).
* @param list the list to be searched.
* @param object the object to be searched for.
* @param comparator the comparator by which the list is ordered.
* @return index of the search object, if it is contained in the list;
* otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.<br>
* The <i>insertion point</i> is defined as the point at which
* the object would be inserted into the list: the index of
* the first element greater than the object, or
* <code>list.size()</code>, if all elements in the list are less
* than the specified object. Note that this guarantees that
* the return value will be ≥ 0 only if the key is
* found.
* @throws ClassCastException if the list contains
* elements that are not <i>mutually comparable</i> using the
* specified comparator, or the search object is not
* <i>mutually comparable</i> with the elements of the list
* using this comparator.
*/
public static <S, T extends S> int firstIndexOf(List<S> list, T object, Comparator<? super S> comparator) {
int left = 0, right = list.size()-1;
while (left <= right) {
int median = (left+right)/2, comparison = comparator.compare(list.get(median), object);
if (comparison < 0)
left = median+1;
else
if (comparison > 0 || left < median && comparator.compare(list.get(median-1), object) == 0)
right = median-1;
else
return median;
}
return -left-1;
}
/**
* Searches the specified list for the first appearance of the
* specified object using the binary search algorithm. The list
* <b>must</b> be sorted into ascending order according to the
* <i>natural ordering</i> of its elements before calling this method.
* If it is not sorted, the results are undefined. If the list
* contains multiple elements equal to the specified object, the first
* appearance will be found.
*
* @param <S> the type of the elements the given list is able to store.
* @param <T> the type of the object to be searched for (must be a subtype
* of S).
* @param list the list to be seached.
* @param object the object to be searched for.
* @return index of the search object, if it is contained in the list;
* otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.<br>
* The <i>insertion point</i> is defined as the point at which
* the object would be inserted into the list: the index of
* the first element greater than the object, or
* <code>list.size()</code>, if all elements in the list are less
* than the specified object. Note that this guarantees that
* the return value will be ≥ 0 only if the key is
* found.
* @throws ClassCastException if the list contains
* elements that are not <i>mutually comparable</i>, or the
* search object is not <i>mutually comparable</i> with the
* elements of the list.
*/
public static <S extends Comparable<S>, T extends S> int firstIndexOf(List<S> list, T object) {
return firstIndexOf(list, object, new ComparableComparator<S>());
}
/**
* Searches the specified list for the last appearance of the
* specified object using the binary search algorithm. The list
* <b>must</b> be sorted into ascending order according to the
* specified comparator before calling this method. If it is not
* sorted, the results are undefined. If the list contains multiple
* elements equal to the specified object, the last appearance will be
* found.
*
* @param <S> the type of the elements the given lsit is able to store.
* @param <T> the type of the object to be searched for (must be a subtype
* of S).
* @param list the list to be searched.
* @param object the object to be searched for.
* @param comparator the comparator by which the list is ordered.
* @return index of the search object, if it is contained in the list;
* otherwise, <code>(-(<i>insertion point</i>) - 1)</code>.<br>
* The <i>insertion point</i> is defined as the point at which
* the object would be inserted into the list: the index of
* the first element greater than the object, or
* <code>list.size()</code>, if all elements in the list are less
* than the specified object. Note that this guarantees that
* the return value will be ≥ 0 only if the key is
* found.
* @throws ClassCastException if the list contains
* elements that are not <i>mutually comparable</i> using the
* specified comparator, or the search object in not
* <i>mutually comparable</i> with the elements of the list
* using this comparator.
*/
public static <S, T extends S> int lastIndexOf(List<S> list, T object, Comparator<? super S> comparator) {
int left = 0, right = list.size()-1;
while (left <= right) {
int median = (left+right)/2, comparison = comparator.compare(list.get(median), object);
if (comparison > 0)
right = median-1;
else
if (comparison < 0 || median < right && comparator.compare(list.get(median+1), object) == 0)
left = median+1;
else
return median;
}
return -left-1;
}
/**
* Searches the specified list for the last appearance of the
* specified object using the binary search algorithm. The list
* <b>must</b> be sorted into ascending order according to the
* <i>natural ordering</i> of its elements before calling this method.
* If it is not sorted, the results are undefined. If the list
* contains multiple elements equal to the specified object, the last
* appearance will be found.
*
* @param <S> the type of the elements the given list is able to store.
* @param <T> the type of the object to be searched for (must be a subtype
* of S).
* @param list the list to be searched.
* @param object the object to be searched for.
* @return index of the search object, if it is contained in the list;
* otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.<br>
* The <i>insertion point</i> is defined as the point at which
* the object would be inserted into the list: the index of
* the first element greater than the object, or
* <tt>list.size()</tt>, if all elements in the list are less
* than the specified object. Note that this guarantees that
* the return value will be ≥ 0 only if the key is
* found.
* @throws ClassCastException if the list contains
* elements that are not <i>mutually comparable</i>, or the
* search object is not <i>mutually comparable</i> with the
* elements of the list.
*/
public static <S extends Comparable<S>, T extends S> int lastIndexOf(List<S> list, T object) {
return lastIndexOf(list, object, new ComparableComparator<S>());
}
/**
* Returns the index of the minimum stored in the list.
*
* @param <E> the type of the elements stored in the list.
* @param list the list to be searched.
* @return the index of the minimum stored in the list or <tt>-1</tt> if
* the list is empty.
*/
public static <E extends Comparable<E>> int indexOfMinimum(List<E> list) {
if (list.size() > 0) {
int index = 0;
E minimum = list.get(index);
for (int i = 1; i < list.size(); i++)
if (list.get(i).compareTo(minimum) < 0)
minimum = list.get(index = i);
return index;
}
return -1;
}
/**
* Returns the index of the maximum stored in the list.
*
* @param <E> the type of the elements stored in the list.
* @param list the list to be searched.
* @return the index of the maximum stored in the list or <tt>-1</tt> if
* the list is empty.
*/
public static <E extends Comparable<E>> int indexOfMaximum(List<E> list) {
if (list.size() > 0) {
int index = 0;
E maximum = list.get(index);
for (int i = 1; i < list.size(); i++)
if (list.get(i).compareTo(maximum) > 0)
maximum = list.get(index = i);
return index;
}
return -1;
}
/**
* Returns a new list containing the specified object <code>times</code>
* times.
*
* @param <T> the type of the objects the list is able to store.
* @param init the object that should be inserted <code>times</times> times
* for initializing the list.
* @param times the number of times the given object should be inserted.
* @return the initialized list containing the specified object
* <code>times</code> times.
*/
public static <T> List<T> initializedList(T init, int times) {
ArrayList<T> list = new ArrayList<T>(times);
for (int i = 0; i < times; i++)
list.add(init);
return list;
}
/**
* Sort the given list by using the quick sort algorithm for lists. The
* specified comparator is used for comparing the elements of the list.
*
* @param <E> the type of the elements stored by the given list.
* @param data the list to be sorted.
* @param comparator the comparator that is used for comparing the elements
* of the list.
*/
public static <E> void quickSort(List<E> data, Comparator<? super E> comparator) {
quickSort(data, 0, data.size()-1, comparator);
}
/**
* This method performs the quick sort algorithm for lists. The given list
* is sorted using the specified comparator. The specified indices
* determine the range of the list that should be sorted by the algorithm.
* For (ranges of) lists with no more than ten elements the bubble sort
* algorithm is used, other (ranges of) lists are sorted by a quick sort
* algorithm using the median of three as pivot element.
*
* @param <E> the type of the elements stored by the given list.
* @param data the list to be sorted.
* @param l the index of the list where the range to be sorted starts.
* @param r the index of the list where the range to be sorted ends.
* @param comparator the comparator that is used for comparing the elements
* of the list.
*/
public static <E> void quickSort(List<E> data, int l, int r, Comparator<? super E> comparator) {
int re, li, mid;
E tmp;
//rekursiv, direktes Tauschen der Elemente
if (r-l < 10)
for (li = l+1; li <= r; li++) {
tmp = data.get(li);
for (re = li; re > l && comparator.compare(tmp, data.get(re-1)) < 0; re--)
data.set(re, data.get(re-1));
data.set(re, tmp);
}
else
while (l < r) {
li = l;
re = r;
mid = (li + re ) / 2; //>>1; // ???
if (comparator.compare(data.get(li), data.get(mid)) > 0)
swap(data, li, mid);
if (comparator.compare(data.get(mid), data.get(re)) > 0)
swap(data, mid, re);
if (comparator.compare(data.get(li), data.get(mid)) > 0)
swap(data, li, mid);
tmp = data.get(mid);
while (li <= re) {
while (comparator.compare(data.get(li), tmp) < 0)
li++;
while (comparator.compare(tmp, data.get(re)) < 0)
re--;
if (li <= re) {
swap(data, li, re);
li++;
re--;
} // end of if
} // end of while
if (l < re)
quickSort(data, l, re, comparator);
l = li;
} // end of while
} //end of quickSort
/**
* This metod swaps the elements of the given list at the specified
* indices.
*
* @param <E> the type of the elements stored by the given list.
* @param data the list containing the elements to be swapped.
* @param l the index of the first element to be swapped.
* @param r the index of the second element to be swapped.
*/
private static <E> void swap(List<E> data, int l, int r) {
E tmp = data.get(l);
data.set(l, data.get(r));
data.set(r, tmp);
}
}