Source for java.util.TreeSet

   1: /* TreeSet.java -- a class providing a TreeMap-backed SortedSet
   2:    Copyright (C) 1999, 2000, 2001, 2004, 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.util;
  40: 
  41: import java.io.IOException;
  42: import java.io.ObjectInputStream;
  43: import java.io.ObjectOutputStream;
  44: import java.io.Serializable;
  45: 
  46: /**
  47:  * This class provides a TreeMap-backed implementation of the SortedSet
  48:  * interface. The elements will be sorted according to their <i>natural
  49:  * order</i>, or according to the provided <code>Comparator</code>.<p>
  50:  *
  51:  * Most operations are O(log n), but there is so much overhead that this
  52:  * makes small sets expensive. Note that the ordering must be <i>consistent
  53:  * with equals</i> to correctly implement the Set interface. If this
  54:  * condition is violated, the set is still well-behaved, but you may have
  55:  * suprising results when comparing it to other sets.<p>
  56:  *
  57:  * This implementation is not synchronized. If you need to share this between
  58:  * multiple threads, do something like:<br>
  59:  * <code>SortedSet s
  60:  *       = Collections.synchronizedSortedSet(new TreeSet(...));</code><p>
  61:  *
  62:  * The iterators are <i>fail-fast</i>, meaning that any structural
  63:  * modification, except for <code>remove()</code> called on the iterator
  64:  * itself, cause the iterator to throw a
  65:  * <code>ConcurrentModificationException</code> rather than exhibit
  66:  * non-deterministic behavior.
  67:  *
  68:  * @author Jon Zeppieri
  69:  * @author Bryce McKinlay
  70:  * @author Eric Blake (ebb9@email.byu.edu)
  71:  * @author Tom Tromey (tromey@redhat.com)
  72:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  73:  * @see Collection
  74:  * @see Set
  75:  * @see HashSet
  76:  * @see LinkedHashSet
  77:  * @see Comparable
  78:  * @see Comparator
  79:  * @see Collections#synchronizedSortedSet(SortedSet)
  80:  * @see TreeMap
  81:  * @since 1.2
  82:  * @status updated to 1.6
  83:  */
  84: public class TreeSet<T> extends AbstractSet<T>
  85:   implements NavigableSet<T>, Cloneable, Serializable
  86: {
  87:   /**
  88:    * Compatible with JDK 1.2.
  89:    */
  90:   private static final long serialVersionUID = -2479143000061671589L;
  91: 
  92:   /**
  93:    * The NavigableMap which backs this Set.
  94:    */
  95:   // Not final because of readObject. This will always be one of TreeMap or
  96:   // TreeMap.SubMap, which both extend AbstractMap.
  97:   private transient NavigableMap<T, String> map;
  98: 
  99:   /**
 100:    * Construct a new TreeSet whose backing TreeMap using the "natural"
 101:    * ordering of keys. Elements that are not mutually comparable will cause
 102:    * ClassCastExceptions down the road.
 103:    *
 104:    * @see Comparable
 105:    */
 106:   public TreeSet()
 107:   {
 108:     map = new TreeMap<T, String>();
 109:   }
 110: 
 111:   /**
 112:    * Construct a new TreeSet whose backing TreeMap uses the supplied
 113:    * Comparator. Elements that are not mutually comparable will cause
 114:    * ClassCastExceptions down the road.
 115:    *
 116:    * @param comparator the Comparator this Set will use
 117:    */
 118:   public TreeSet(Comparator<? super T> comparator)
 119:   {
 120:     map = new TreeMap<T, String>(comparator);
 121:   }
 122: 
 123:   /**
 124:    * Construct a new TreeSet whose backing TreeMap uses the "natural"
 125:    * orering of the keys and which contains all of the elements in the
 126:    * supplied Collection. This runs in n*log(n) time.
 127:    *
 128:    * @param collection the new Set will be initialized with all
 129:    *        of the elements in this Collection
 130:    * @throws ClassCastException if the elements of the collection are not
 131:    *         comparable
 132:    * @throws NullPointerException if the collection is null
 133:    * @see Comparable
 134:    */
 135:   public TreeSet(Collection<? extends T> collection)
 136:   {
 137:     map = new TreeMap<T, String>();
 138:     addAll(collection);
 139:   }
 140: 
 141:   /**
 142:    * Construct a new TreeSet, using the same key ordering as the supplied
 143:    * SortedSet and containing all of the elements in the supplied SortedSet.
 144:    * This constructor runs in linear time.
 145:    *
 146:    * @param sortedSet the new TreeSet will use this SortedSet's comparator
 147:    *        and will initialize itself with all its elements
 148:    * @throws NullPointerException if sortedSet is null
 149:    */
 150:   public TreeSet(SortedSet<T> sortedSet)
 151:   {
 152:     Iterator<T> itr;
 153: 
 154:     map = new TreeMap<T, String>
 155:       ((Comparator<? super T>)sortedSet.comparator());
 156:     itr = ((SortedSet<T>) sortedSet).iterator();
 157:     ((TreeMap<T, String>) map).putKeysLinear(itr, sortedSet.size());
 158:   }
 159: 
 160:   /**
 161:    * This private constructor is used to implement the subSet() calls around
 162:    * a backing TreeMap.SubMap.
 163:    *
 164:    * @param backingMap the submap
 165:    */
 166:   private TreeSet(NavigableMap<T,String> backingMap)
 167:   {
 168:     map = backingMap;
 169:   }
 170: 
 171:   /**
 172:    * Adds the spplied Object to the Set if it is not already in the Set;
 173:    * returns true if the element is added, false otherwise.
 174:    *
 175:    * @param obj the Object to be added to this Set
 176:    * @throws ClassCastException if the element cannot be compared with objects
 177:    *         already in the set
 178:    */
 179:   public boolean add(T obj)
 180:   {
 181:     return map.put(obj, "") == null;
 182:   }
 183: 
 184:   /**
 185:    * Adds all of the elements in the supplied Collection to this TreeSet.
 186:    *
 187:    * @param c The collection to add
 188:    * @return true if the Set is altered, false otherwise
 189:    * @throws NullPointerException if c is null
 190:    * @throws ClassCastException if an element in c cannot be compared with
 191:    *         objects already in the set
 192:    */
 193:   public boolean addAll(Collection<? extends T> c)
 194:   {
 195:     boolean result = false;
 196:     int pos = c.size();
 197:     Iterator<? extends T> itr = c.iterator();
 198:     while (--pos >= 0)
 199:       result |= (map.put(itr.next(), "") == null);
 200:     return result;
 201:   }
 202: 
 203:   /**
 204:    * Removes all elements in this Set.
 205:    */
 206:   public void clear()
 207:   {
 208:     map.clear();
 209:   }
 210: 
 211:   /**
 212:    * Returns a shallow copy of this Set. The elements are not cloned.
 213:    *
 214:    * @return the cloned set
 215:    */
 216:   public Object clone()
 217:   {
 218:     TreeSet<T> copy = null;
 219:     try
 220:       {
 221:         copy = (TreeSet<T>) super.clone();
 222:         // Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts.
 223:         copy.map = (NavigableMap<T, String>) ((AbstractMap<T, String>) map).clone();
 224:       }
 225:     catch (CloneNotSupportedException x)
 226:       {
 227:         // Impossible result.
 228:       }
 229:     return copy;
 230:   }
 231: 
 232:   /**
 233:    * Returns this Set's comparator.
 234:    *
 235:    * @return the comparator, or null if the set uses natural ordering
 236:    */
 237:   public Comparator<? super T> comparator()
 238:   {
 239:     return map.comparator();
 240:   }
 241: 
 242:   /**
 243:    * Returns true if this Set contains the supplied Object, false otherwise.
 244:    *
 245:    * @param obj the Object to check for
 246:    * @return true if it is in the set
 247:    * @throws ClassCastException if obj cannot be compared with objects
 248:    *         already in the set
 249:    */
 250:   public boolean contains(Object obj)
 251:   {
 252:     return map.containsKey(obj);
 253:   }
 254: 
 255:   /**
 256:    * Returns the first (by order) element in this Set.
 257:    *
 258:    * @return the first element
 259:    * @throws NoSuchElementException if the set is empty
 260:    */
 261:   public T first()
 262:   {
 263:     return map.firstKey();
 264:   }
 265: 
 266:   /**
 267:    * Returns a view of this Set including all elements less than
 268:    * <code>to</code>. The returned set is backed by the original, so changes
 269:    * in one appear in the other. The subset will throw an
 270:    * {@link IllegalArgumentException} for any attempt to access or add an
 271:    * element beyond the specified cutoff. The returned set does not include
 272:    * the endpoint; if you want inclusion, pass the successor element or
 273:    * call {@link #headSet(T,boolean)}.  This call is equivalent to
 274:    * <code>headSet(to, false)</code>.
 275:    *
 276:    * @param to the (exclusive) cutoff point
 277:    * @return a view of the set less than the cutoff
 278:    * @throws ClassCastException if <code>to</code> is not compatible with
 279:    *         the comparator (or is not Comparable, for natural ordering)
 280:    * @throws NullPointerException if to is null, but the comparator does not
 281:    *         tolerate null elements
 282:    */
 283:   public SortedSet<T> headSet(T to)
 284:   {
 285:     return headSet(to, false);
 286:   }
 287: 
 288:   /**
 289:    * Returns a view of this Set including all elements less than
 290:    * (or equal to, if <code>inclusive</code> is true) <code>to</code>.
 291:    * The returned set is backed by the original, so changes
 292:    * in one appear in the other. The subset will throw an
 293:    * {@link IllegalArgumentException} for any attempt to access or add an
 294:    * element beyond the specified cutoff. 
 295:    *
 296:    * @param to the cutoff point
 297:    * @param inclusive true if <code>to</code> should be included.
 298:    * @return a view of the set for the specified range.
 299:    * @throws ClassCastException if <code>to</code> is not compatible with
 300:    *         the comparator (or is not Comparable, for natural ordering)
 301:    * @throws NullPointerException if to is null, but the comparator does not
 302:    *         tolerate null elements
 303:    */
 304:   public NavigableSet<T> headSet(T to, boolean inclusive)
 305:   {
 306:     return new TreeSet<T>(map.headMap(to, inclusive));
 307:   }
 308: 
 309:   /**
 310:    * Returns true if this Set has size 0, false otherwise.
 311:    *
 312:    * @return true if the set is empty
 313:    */
 314:   public boolean isEmpty()
 315:   {
 316:     return map.isEmpty();
 317:   }
 318: 
 319:   /**
 320:    * Returns in Iterator over the elements in this TreeSet, which traverses
 321:    * in ascending order.
 322:    *
 323:    * @return an iterator
 324:    */
 325:   public Iterator<T> iterator()
 326:   {
 327:     return map.keySet().iterator();
 328:   }
 329: 
 330:   /**
 331:    * Returns the last (by order) element in this Set.
 332:    *
 333:    * @return the last element
 334:    * @throws NoSuchElementException if the set is empty
 335:    */
 336:   public T last()
 337:   {
 338:     return map.lastKey();
 339:   }
 340: 
 341:   /**
 342:    * If the supplied Object is in this Set, it is removed, and true is
 343:    * returned; otherwise, false is returned.
 344:    *
 345:    * @param obj the Object to remove from this Set
 346:    * @return true if the set was modified
 347:    * @throws ClassCastException if obj cannot be compared to set elements
 348:    */
 349:   public boolean remove(Object obj)
 350:   {
 351:     return map.remove(obj) != null;
 352:   }
 353: 
 354:   /**
 355:    * Returns the number of elements in this Set
 356:    *
 357:    * @return the set size
 358:    */
 359:   public int size()
 360:   {
 361:     return map.size();
 362:   }
 363: 
 364:   /**
 365:    * Returns a view of this Set including all elements greater or equal to
 366:    * <code>from</code> and less than <code>to</code> (a half-open interval).
 367:    * The returned set is backed by the original, so changes in one appear in
 368:    * the other. The subset will throw an {@link IllegalArgumentException}
 369:    * for any attempt to access or add an element beyond the specified cutoffs.
 370:    * The returned set includes the low endpoint but not the high; if you want
 371:    * to reverse this behavior on either end, pass in the successor element
 372:    * or call {@link #subSet(T,boolean,T,boolean)}.  This is equivalent to
 373:    * calling <code>subSet(from,true,to,false)</code>.
 374:    *
 375:    * @param from the (inclusive) low cutoff point
 376:    * @param to the (exclusive) high cutoff point
 377:    * @return a view of the set between the cutoffs
 378:    * @throws ClassCastException if either cutoff is not compatible with
 379:    *         the comparator (or is not Comparable, for natural ordering)
 380:    * @throws NullPointerException if from or to is null, but the comparator
 381:    *         does not tolerate null elements
 382:    * @throws IllegalArgumentException if from is greater than to
 383:    */
 384:   public SortedSet<T> subSet(T from, T to)
 385:   {
 386:     return subSet(from, true, to, false);
 387:   }
 388: 
 389:   /**
 390:    * Returns a view of this Set including all elements greater than (or equal to,
 391:    * if <code>fromInclusive</code> is true</code> <code>from</code> and less than
 392:    * (or equal to, if <code>toInclusive</code> is true) <code>to</code>.
 393:    * The returned set is backed by the original, so changes in one appear in
 394:    * the other. The subset will throw an {@link IllegalArgumentException}
 395:    * for any attempt to access or add an element beyond the specified cutoffs.
 396:    *
 397:    * @param from the low cutoff point
 398:    * @param fromInclusive true if <code>from</code> should be included.
 399:    * @param to the high cutoff point
 400:    * @param toInclusive true if <code>to</code> should be included.
 401:    * @return a view of the set for the specified range.
 402:    * @throws ClassCastException if either cutoff is not compatible with
 403:    *         the comparator (or is not Comparable, for natural ordering)
 404:    * @throws NullPointerException if from or to is null, but the comparator
 405:    *         does not tolerate null elements
 406:    * @throws IllegalArgumentException if from is greater than to
 407:    */
 408:   public NavigableSet<T> subSet(T from, boolean fromInclusive,
 409:                 T to, boolean toInclusive)
 410:   {
 411:     return new TreeSet<T>(map.subMap(from, fromInclusive,
 412:                      to, toInclusive));
 413:   }
 414: 
 415:   /**
 416:    * Returns a view of this Set including all elements greater or equal to
 417:    * <code>from</code>. The returned set is backed by the original, so
 418:    * changes in one appear in the other. The subset will throw an
 419:    * {@link IllegalArgumentException} for any attempt to access or add an
 420:    * element beyond the specified cutoff. The returned set includes the
 421:    * endpoint; if you want to exclude it, pass in the successor element
 422:    * or call {@link #tailSet(T,boolean)}.  This is equivalent to calling
 423:    * <code>tailSet(from, true)</code>.
 424:    *
 425:    * @param from the (inclusive) low cutoff point
 426:    * @return a view of the set above the cutoff
 427:    * @throws ClassCastException if <code>from</code> is not compatible with
 428:    *         the comparator (or is not Comparable, for natural ordering)
 429:    * @throws NullPointerException if from is null, but the comparator
 430:    *         does not tolerate null elements
 431:    */
 432:   public SortedSet<T> tailSet(T from)
 433:   {
 434:     return tailSet(from, true);
 435:   }
 436: 
 437:   /**
 438:    * Returns a view of this Set including all elements greater (or equal to,
 439:    * if <code>inclusive</code> is true) <code>from</code>. The returned set
 440:    * is backed by the original, so changes in one appear in the other. The
 441:    * subset will throw an {@link IllegalArgumentException} for any attempt
 442:    * to access or add an element beyond the specified cutoff.
 443:    *
 444:    * @param from the low cutoff point.
 445:    * @param inclusive true if <code>from</code> should be included.
 446:    * @return a view of the set for the specified range.
 447:    * @throws ClassCastException if <code>from</code> is not compatible with
 448:    *         the comparator (or is not Comparable, for natural ordering)
 449:    * @throws NullPointerException if from is null, but the comparator
 450:    *         does not tolerate null elements
 451:    */
 452:   public NavigableSet<T> tailSet(T from, boolean inclusive)
 453:   {
 454:     return new TreeSet<T>(map.tailMap(from, inclusive));
 455:   }
 456: 
 457:   /**
 458:    * Serializes this object to the given stream.
 459:    *
 460:    * @param s the stream to write to
 461:    * @throws IOException if the underlying stream fails
 462:    * @serialData the <i>comparator</i> (Object), followed by the set size
 463:    *             (int), the the elements in sorted order (Object)
 464:    */
 465:   private void writeObject(ObjectOutputStream s) throws IOException
 466:   {
 467:     s.defaultWriteObject();
 468:     Iterator<T> itr = map.keySet().iterator();
 469:     int pos = map.size();
 470:     s.writeObject(map.comparator());
 471:     s.writeInt(pos);
 472:     while (--pos >= 0)
 473:       s.writeObject(itr.next());
 474:   }
 475: 
 476:   /**
 477:    * Deserializes this object from the given stream.
 478:    *
 479:    * @param s the stream to read from
 480:    * @throws ClassNotFoundException if the underlying stream fails
 481:    * @throws IOException if the underlying stream fails
 482:    * @serialData the <i>comparator</i> (Object), followed by the set size
 483:    *             (int), the the elements in sorted order (Object)
 484:    */
 485:   private void readObject(ObjectInputStream s)
 486:     throws IOException, ClassNotFoundException
 487:   {
 488:     s.defaultReadObject();
 489:     Comparator<? super T> comparator = (Comparator<? super T>) s.readObject();
 490:     int size = s.readInt();
 491:     map = new TreeMap<T, String>(comparator);
 492:     ((TreeMap<T, String>) map).putFromObjStream(s, size, false);
 493:   }
 494: 
 495:   /**
 496:    * Returns the least or lowest element in the set greater than or
 497:    * equal to the given element, or <code>null</code> if there is
 498:    * no such element.
 499:    *
 500:    * @param e the element relative to the returned element.
 501:    * @return the least element greater than or equal
 502:    *         to the given element, or <code>null</code> if there is
 503:    *         no such element.
 504:    * @throws ClassCastException if the specified element can not
 505:    *                            be compared with those in the map.
 506:    * @throws NullPointerException if the element is <code>null</code>
 507:    *                              and this set either uses natural
 508:    *                              ordering or a comparator that does
 509:    *                              not permit null elements.
 510:    * @since 1.6
 511:    */
 512:   public T ceiling(T e)
 513:   {
 514:     return map.ceilingKey(e);
 515:   }
 516: 
 517:   /**
 518:    * Returns an iterator over the elements of this set in descending
 519:    * order.  This is equivalent to calling
 520:    * <code>descendingSet().iterator()</code>.
 521:    *
 522:    * @return an iterator over the elements in descending order.
 523:    * @since 1.6
 524:    */
 525:   public Iterator<T> descendingIterator()
 526:   {
 527:     return descendingSet().iterator();
 528:   }
 529: 
 530:   /**
 531:    * Returns a view of the set in reverse order.  The descending set
 532:    * is backed by the original set, so that changes affect both sets.
 533:    * Any changes occurring to either set while an iteration is taking
 534:    * place (with the exception of a {@link Iterator#remove()} operation)
 535:    * result in undefined behaviour from the iteration.  The ordering
 536:    * of the descending set is the same as for a set with a
 537:    * {@link Comparator} given by {@link Collections#reverseOrder()},
 538:    * and calling {@link #descendingSet()} on the descending set itself
 539:    * results in a view equivalent to the original set.
 540:    *
 541:    * @return a reverse order view of the set.
 542:    * @since 1.6
 543:    */
 544:   public NavigableSet<T> descendingSet()
 545:   {
 546:     return map.descendingKeySet();
 547:   }
 548: 
 549:   /**
 550:    * Returns the greatest or highest element in the set less than or
 551:    * equal to the given element, or <code>null</code> if there is
 552:    * no such element.
 553:    *
 554:    * @param e the element relative to the returned element.
 555:    * @return the greatest element less than or equal
 556:    *         to the given element, or <code>null</code> if there is
 557:    *         no such element.
 558:    * @throws ClassCastException if the specified element can not
 559:    *                            be compared with those in the map.
 560:    * @throws NullPointerException if the element is <code>null</code>
 561:    *                              and this set either uses natural
 562:    *                              ordering or a comparator that does
 563:    *                              not permit null elements.
 564:    * @since 1.6
 565:    */
 566:   public T floor(T e)
 567:   {
 568:     return map.floorKey(e);
 569:   }
 570: 
 571:   /**
 572:    * Returns the least or lowest element in the set strictly greater
 573:    * than the given element, or <code>null</code> if there is
 574:    * no such element.
 575:    *
 576:    * @param e the element relative to the returned element.
 577:    * @return the least element greater than 
 578:    *         the given element, or <code>null</code> if there is
 579:    *         no such element.
 580:    * @throws ClassCastException if the specified element can not
 581:    *                            be compared with those in the map.
 582:    * @throws NullPointerException if the element is <code>null</code>
 583:    *                              and this set either uses natural
 584:    *                              ordering or a comparator that does
 585:    *                              not permit null elements.
 586:    * @since 1.6
 587:    */
 588:   public T higher(T e)
 589:   {
 590:     return map.higherKey(e);
 591:   }
 592: 
 593:   /**
 594:    * Returns the greatest or highest element in the set strictly less
 595:    * than the given element, or <code>null</code> if there is
 596:    * no such element.
 597:    *
 598:    * @param e the element relative to the returned element.
 599:    * @return the greatest element less than 
 600:    *         the given element, or <code>null</code> if there is
 601:    *         no such element.
 602:    * @throws ClassCastException if the specified element can not
 603:    *                            be compared with those in the map.
 604:    * @throws NullPointerException if the element is <code>null</code>
 605:    *                              and this set either uses natural
 606:    *                              ordering or a comparator that does
 607:    *                              not permit null elements.
 608:    * @since 1.6
 609:    */
 610:   public T lower(T e)
 611:   {
 612:     return map.lowerKey(e);
 613:   }
 614: 
 615:   /**
 616:    * Removes and returns the least or lowest element in the set,
 617:    * or <code>null</code> if the map is empty.
 618:    *
 619:    * @return the removed first element, or <code>null</code> if the
 620:    *         map is empty.
 621:    * @since 1.6
 622:    */
 623:   public T pollFirst()
 624:   {
 625:     return map.pollFirstEntry().getKey();
 626:   }
 627: 
 628:   /**
 629:    * Removes and returns the greatest or highest element in the set,
 630:    * or <code>null</code> if the map is empty.
 631:    *
 632:    * @return the removed last element, or <code>null</code> if the
 633:    *         map is empty.
 634:    * @since 1.6
 635:    */
 636:   public T pollLast()
 637:   {
 638:     return map.pollLastEntry().getKey();
 639:   }
 640: 
 641: }