/* 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.AbstractSet; import java.util.Comparator; import java.util.Iterator; import xxl.core.binarySearchTrees.BinarySearchTree; import xxl.core.comparators.ComparableComparator; import xxl.core.cursors.mappers.Mapper; import xxl.core.functions.AbstractFunction; import xxl.core.functions.Function; import xxl.core.functions.Identity; import xxl.core.predicates.Predicates; /** * This class provides an implementation of the Set interface that * internally uses a binary search tree to store its elements. <p> * * The performance of the set depends on the performance of the internally * used binary search tree (e.g., an avl tree guaratees that insertion, * removal and searching requires logarithmic time, but binary search * trees can be degenerated).<p> * * The iterators returned by this class' <tt>iterator</tt> method are * <i>fail-fast</i>: if the set is structurally modified at any time after * the iterator is created, in any way except through the iterator's own * <tt>remove</tt> method, the iterator will throw a * ConcurrentModificationException. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than * risking arbitrary, non-deterministic behavior at an undetermined time * in the future.<p> * * Example usage (1). * <pre> * // create a binary search tree set that is using a binary search tree and the natural * // ordering of the elements * * BinarySearchTreeSet set = new BinarySearchTreeSet(); * * // create a new iterator with 100 random number lower than 1000 * * Iterator iterator = new DiscreteRandomNumber(new JavaDiscreteRandomWrapper(1000), 100); * * // insert all elements of the given iterator * * while (iterator.hasNext()) * set.insert(iterator.next()); * * // create an iteration of the elements of the set * * iterator = set.iterator(); * * // print all elements of the iteration (set) * * while (iterator.hasNext()) * System.out.println(iterator.next()); * </pre> * * @see AbstractSet * @see BinarySearchTree * @see ComparableComparator * @see Comparator * @see Function * @see Iterator * @see Mapper */ public class BinarySearchTreeSet extends AbstractSet { /** * The binary search tree is internally used to store the elements of * the set. */ protected BinarySearchTree tree; /** * The comparator to determine the order of the set (and the * internally used binary search tree). More exactly, there can be * three different cases when two elements * <tt>o1</tt> and <tt>o2</tt> are inserted into the set * <ul> * <dl> * <dt><li><tt>comparator.compare(o1, o2) < 0</tt> :</dt> * <dd>the set returns <tt>o1</tt> prior to returning <tt>o2</tt>.</dd> * <dt><li><tt>comparator.compare(o1, o2) == 0</tt> :</dt> * <dd>when inserting equal elements (determined by the used * comparator), there is no guarantee which one will be returned * first. * <dt><li><tt>comparator.compare(o1, o2) > 0</tt> :</dt> * <dd>the set returns <tt>o2</tt> prior to returning <tt>o1</tt>.</dd> * </dl> * </ul> */ protected Comparator comparator; /** * The comparator to determine the subtree of a node of a binary * search tree that would be used to insert a given object. The * compare method of the comparator is called with an array * (<i>parameter list</i>) of objects (to insert) and a node of a * binary search tree. */ protected Comparator chooseSubtree = new Comparator () { public int compare (Object object0, Object object1) { return comparator.compare(((Object[]) object0)[0], ((BinarySearchTree.Node)object1).object()); } }; /** * Constructs a new binary search tree set that initializes the * internally used binary search tree with a new tree and uses the * specified comparator to order elements when inserted. The specified * function is used to create a new binary search tree (it works * like the {@link BinarySearchTree#FACTORY_METHOD FACTORY_METHOD} of * BinarySearchTree). * * @param comparator the comparator to determine the order of the * set. * @param newBinarySearchTree a function to create a new binary search * tree. */ public BinarySearchTreeSet (Comparator comparator, Function newBinarySearchTree) { (this.tree = (BinarySearchTree) newBinarySearchTree.invoke( Predicates.TRUE, Identity.DEFAULT_INSTANCE) ).clear(); this.comparator = comparator; } /** * Constructs a new binary search tree set that uses the specified * comparator to order elements when inserted. The internally used * binary search tree is initialized by the FACTORY_METHOD of * BinarySearchTree). This constructor is equivalent to the call of * <code>BinarySearchTreeSet(comparator, BinarySearchTree.FACTORY_METHOD)</code>. * * @param comparator the comparator to determine the order of the * set. * @see BinarySearchTree#FACTORY_METHOD */ public BinarySearchTreeSet (Comparator comparator) { this(comparator, BinarySearchTree.FACTORY_METHOD); } /** * Constructs a new binary search tree set that initializes the * internally used binary search tree with a new tree and uses the * <i>natural ordering</i> of its element to order them. The specified * function is used to create a new binary search tree (it works * like the {@link BinarySearchTree#FACTORY_METHOD FACTORY_METHOD} of * BinarySearchTree). This constructor is equivalent to the call of * <code>BinarySearchTreeSet(ComparableComparator.DEFAULT_INSTANCE, newBinarySearchTree)</code>. * * @param newBinarySearchTree a function to create a new binary search * tree. */ public BinarySearchTreeSet (Function newBinarySearchTree) { this(new ComparableComparator(), newBinarySearchTree); } /** * Constructs a new binary search tree set that uses the <i>natural * ordering</i> of its elements to order them. This constructor is * equivalent to the call of * <code>BinarySearchTreeSet(ComparableComparator.DEFAULT_INSTANCE, BinarySearchTree.FACTORY_METHOD)</code>. * * @see BinarySearchTree#FACTORY_METHOD */ public BinarySearchTreeSet () { this(new ComparableComparator()); } /** * Removes all elements from this set. This set will be empty * after this call returns (unless it throws an exception). */ public void clear () { tree.clear(); } /** * Returns the number of elements in this set (its cardinality). If * this set contains more than <tt>Integer.MAX_VALUE</tt> elements, * <tt>Integer.MAX_VALUE</tt> is returned. * * @return the number of elements in this set (its cardinality). */ public int size () { return tree.size(); } /** * Returns an iterator over the elements in this set. The elements are * returned in the order determined by the comparator. * * @return an iterator over the elements in this set. */ public Iterator iterator () { return new Mapper( new AbstractFunction () { public Object invoke (Object node) { return ((BinarySearchTree.Node)node).object(); } }, tree.iterator() ); } /** * Returns true if this set contains the specified element. More * formally, returns true if and only if this set contains an element * <tt>e</tt> such that * (<tt>object==null ? e==null : object.equals(e)</tt>). * * @param object the element whose presence in this set is to be tested. * @return true if this set contains the specified element. */ public boolean contains (Object object) { int[] result = new int[1]; return tree.get(chooseSubtree, new Object [] {object}, result)!=null && result[0]==0; } /** * Adds the specified element to this set if it is not already * present. More formally, adds the specified element to this set if * this set contains no element <tt>e</tt> such that * (<tt>o==null ? e==null : o.equals(e)</tt>). If this set already * contains the specified element, the call leaves this set unchanged. * * @param object the element to be added to this set. * @return the element that is added to this set. */ public Object insert (Object object) { BinarySearchTree.Node node = tree.insert(chooseSubtree, new Object [] {object}); return node==null? null: node.object(); } /** * Removes the specified element from this set if it is present. More * formally, removes an element <tt>e</tt> such that * (<tt>object==null ? e==null : object.equals(e)</tt>), if the set * contains such an element. Returns true if the set contained the * specified element. * * @param object the object to be removed from this set, if present. * @return true if the set contained the specified element. * @throws UnsupportedOperationException if the <tt>remove</tt> method * is not supported by this set. */ public boolean remove (Object object) throws UnsupportedOperationException { BinarySearchTree.Node node = tree.remove(chooseSubtree, new Object [] {object}, size()%2); return node!=null; } }