1 |
/* TreeSet.java -- a class providing a TreeMap-backet SortedSet |
/* TreeSet.java -- a class providing a TreeMap-backed SortedSet |
2 |
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. |
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
33 |
import java.io.ObjectOutputStream; |
import java.io.ObjectOutputStream; |
34 |
|
|
35 |
/** |
/** |
36 |
* This class provides a TreeMap-backed implementation of the |
* This class provides a TreeMap-backed implementation of the SortedSet |
37 |
* SortedSet interface. |
* interface. The elements will be sorted according to their <i>natural |
38 |
|
* order</i>, or according to the provided <code>Comparator</code>.<p> |
39 |
* |
* |
40 |
* Each element in the Set is a key in the backing TreeMap; each key |
* Most operations are O(log n), but there is so much overhead that this |
41 |
* maps to a static token, denoting that the key does, in fact, exist. |
* makes small sets expensive. Note that the ordering must be <i>consistent |
42 |
|
* with equals</i> to correctly implement the Set interface. If this |
43 |
|
* condition is violated, the set is still well-behaved, but you may have |
44 |
|
* suprising results when comparing it to other sets.<p> |
45 |
* |
* |
46 |
* Most operations are O(log n). |
* This implementation is not synchronized. If you need to share this between |
47 |
|
* multiple threads, do something like:<br> |
48 |
|
* <code>SortedSet s |
49 |
|
* = Collections.synchronizedSortedSet(new TreeSet(...));</code><p> |
50 |
* |
* |
51 |
* TreeSet is a part of the JDK1.2 Collections API. |
* The iterators are <i>fail-fast</i>, meaning that any structural |
52 |
|
* modification, except for <code>remove()</code> called on the iterator |
53 |
|
* itself, cause the iterator to throw a |
54 |
|
* <code>ConcurrentModificationException</code> rather than exhibit |
55 |
|
* non-deterministic behavior. |
56 |
* |
* |
57 |
* @author Jon Zeppieri |
* @author Jon Zeppieri |
58 |
|
* @author Eric Blake <ebb9@email.byu.edu> |
59 |
|
* @see Collection |
60 |
|
* @see Set |
61 |
|
* @see HashSet |
62 |
|
* @see LinkedHashSet |
63 |
|
* @see Comparable |
64 |
|
* @see Comparator |
65 |
|
* @see Collections#synchronizedSortedSet(SortedSet) |
66 |
|
* @see TreeMap |
67 |
|
* @since 1.2 |
68 |
|
* @status updated to 1.4 |
69 |
*/ |
*/ |
|
|
|
70 |
public class TreeSet extends AbstractSet |
public class TreeSet extends AbstractSet |
71 |
implements SortedSet, Cloneable, Serializable |
implements SortedSet, Cloneable, Serializable |
72 |
{ |
{ |
73 |
/** The TreeMap which backs this Set */ |
/** |
74 |
transient SortedMap map; |
* Compatible with JDK 1.2. |
75 |
|
*/ |
76 |
|
private static final long serialVersionUID = -2479143000061671589L; |
77 |
|
|
78 |
static final long serialVersionUID = -2479143000061671589L; |
/** |
79 |
|
* The SortedMap which backs this Set. |
80 |
|
*/ |
81 |
|
// Not final because of readObject. This will always be one of TreeMap or |
82 |
|
// TreeMap.SubMap, which both extend AbstractMap. |
83 |
|
private transient SortedMap map; |
84 |
|
|
85 |
/** |
/** |
86 |
* Construct a new TreeSet whose backing TreeMap using the "natural" |
* Construct a new TreeSet whose backing TreeMap using the "natural" |
87 |
* ordering of keys. |
* ordering of keys. Elements that are not mutually comparable will cause |
88 |
|
* ClassCastExceptions down the road. |
89 |
|
* |
90 |
|
* @see Comparable |
91 |
*/ |
*/ |
92 |
public TreeSet() |
public TreeSet() |
93 |
{ |
{ |
94 |
map = new TreeMap(); |
map = new TreeMap(); |
95 |
} |
} |
96 |
|
|
97 |
/** |
/** |
98 |
* Construct a new TreeSet whose backing TreeMap uses the supplied |
* Construct a new TreeSet whose backing TreeMap uses the supplied |
99 |
* Comparator. |
* Comparator. Elements that are not mutually comparable will cause |
100 |
|
* ClassCastExceptions down the road. |
101 |
* |
* |
102 |
* @param oComparator the Comparator this Set will use |
* @param comparator the Comparator this Set will use |
103 |
*/ |
*/ |
104 |
public TreeSet(Comparator comparator) |
public TreeSet(Comparator comparator) |
105 |
{ |
{ |
106 |
map = new TreeMap(comparator); |
map = new TreeMap(comparator); |
107 |
} |
} |
108 |
|
|
109 |
/** |
/** |
110 |
* Construct a new TreeSet whose backing TreeMap uses the "natural" |
* Construct a new TreeSet whose backing TreeMap uses the "natural" |
111 |
* orering of the keys and which contains all of the elements in the |
* orering of the keys and which contains all of the elements in the |
112 |
* supplied Collection. |
* supplied Collection. This runs in n*log(n) time. |
113 |
* |
* |
114 |
* @param oCollection the new Set will be initialized with all |
* @param collection the new Set will be initialized with all |
115 |
* of the elements in this Collection |
* of the elements in this Collection |
116 |
|
* @throws ClassCastException if the elements of the collection are not |
117 |
|
* comparable |
118 |
|
* @throws NullPointerException if the collection is null |
119 |
|
* @see Comparable |
120 |
*/ |
*/ |
121 |
public TreeSet(Collection collection) |
public TreeSet(Collection collection) |
122 |
{ |
{ |
129 |
* SortedSet and containing all of the elements in the supplied SortedSet. |
* SortedSet and containing all of the elements in the supplied SortedSet. |
130 |
* This constructor runs in linear time. |
* This constructor runs in linear time. |
131 |
* |
* |
132 |
* @param sortedSet the new TreeSet will use this SortedSet's |
* @param sortedSet the new TreeSet will use this SortedSet's comparator |
133 |
* comparator and will initialize itself |
* and will initialize itself with all its elements |
134 |
* with all of the elements in this SortedSet |
* @throws NullPointerException if sortedSet is null |
135 |
*/ |
*/ |
136 |
public TreeSet(SortedSet sortedSet) |
public TreeSet(SortedSet sortedSet) |
137 |
{ |
{ |
138 |
TreeMap map = new TreeMap(sortedSet.comparator()); |
map = new TreeMap(sortedSet.comparator()); |
|
int i = 0; |
|
139 |
Iterator itr = sortedSet.iterator(); |
Iterator itr = sortedSet.iterator(); |
140 |
map.putKeysLinear(itr, sortedSet.size()); |
((TreeMap) map).putKeysLinear(itr, sortedSet.size()); |
|
this.map = map; |
|
141 |
} |
} |
142 |
|
|
143 |
/* This private constructor is used to implement the subSet() calls around |
/** |
144 |
a backing TreeMap.SubMap. */ |
* This private constructor is used to implement the subSet() calls around |
145 |
TreeSet(SortedMap backingMap) |
* a backing TreeMap.SubMap. |
146 |
|
* |
147 |
|
* @param backingMap the submap |
148 |
|
*/ |
149 |
|
private TreeSet(SortedMap backingMap) |
150 |
{ |
{ |
151 |
map = backingMap; |
map = backingMap; |
152 |
} |
} |
153 |
|
|
154 |
/** |
/** |
155 |
* Adds the spplied Object to the Set if it is not already in the Set; |
* Adds the spplied Object to the Set if it is not already in the Set; |
156 |
* returns true if the element is added, false otherwise |
* returns true if the element is added, false otherwise. |
157 |
* |
* |
158 |
* @param obj the Object to be added to this Set |
* @param obj the Object to be added to this Set |
159 |
|
* @throws ClassCastException if the element cannot be compared with objects |
160 |
|
* already in the set |
161 |
*/ |
*/ |
162 |
public boolean add(Object obj) |
public boolean add(Object obj) |
163 |
{ |
{ |
164 |
return (map.put(obj, Boolean.TRUE) == null); |
return map.put(obj, "") == null; |
165 |
} |
} |
166 |
|
|
167 |
/** |
/** |
168 |
* Adds all of the elements in the supplied Collection to this TreeSet. |
* Adds all of the elements in the supplied Collection to this TreeSet. |
169 |
* |
* |
170 |
* @param c All of the elements in this Collection |
* @param c The collection to add |
171 |
* will be added to the Set. |
* @return true if the Set is altered, false otherwise |
172 |
* |
* @throws NullPointerException if c is null |
173 |
* @return true if the Set is altered, false otherwise |
* @throws ClassCastException if an element in c cannot be compared with |
174 |
|
* objects already in the set |
175 |
*/ |
*/ |
176 |
public boolean addAll(Collection c) |
public boolean addAll(Collection c) |
177 |
{ |
{ |
178 |
boolean result = false; |
boolean result = false; |
179 |
int size = c.size(); |
int pos = c.size(); |
180 |
Iterator itr = c.iterator(); |
Iterator itr = c.iterator(); |
181 |
|
while (--pos >= 0) |
182 |
for (int i = 0; i < size; i++) |
result |= (map.put(itr.next(), "") == null); |
|
result |= (map.put(itr.next(), Boolean.TRUE) == null); |
|
|
|
|
183 |
return result; |
return result; |
184 |
} |
} |
185 |
|
|
191 |
map.clear(); |
map.clear(); |
192 |
} |
} |
193 |
|
|
194 |
/** Returns a shallow copy of this Set. */ |
/** |
195 |
|
* Returns a shallow copy of this Set. The elements are not cloned. |
196 |
|
* |
197 |
|
* @return the cloned set |
198 |
|
*/ |
199 |
public Object clone() |
public Object clone() |
200 |
{ |
{ |
201 |
TreeSet copy = null; |
TreeSet copy = null; |
202 |
try |
try |
203 |
{ |
{ |
204 |
copy = (TreeSet) super.clone(); |
copy = (TreeSet) super.clone(); |
205 |
|
// Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts. |
206 |
|
copy.map = (SortedMap) ((AbstractMap) map).clone(); |
207 |
} |
} |
208 |
catch (CloneNotSupportedException x) |
catch (CloneNotSupportedException x) |
209 |
{ |
{ |
210 |
|
// Impossible result. |
211 |
} |
} |
|
copy.map = (SortedMap) ((TreeMap) map).clone(); |
|
212 |
return copy; |
return copy; |
213 |
} |
} |
214 |
|
|
215 |
/** Returns this Set's comparator */ |
/** |
216 |
|
* Returns this Set's comparator. |
217 |
|
* |
218 |
|
* @return the comparator, or null if the set uses natural ordering |
219 |
|
*/ |
220 |
public Comparator comparator() |
public Comparator comparator() |
221 |
{ |
{ |
222 |
return map.comparator(); |
return map.comparator(); |
223 |
} |
} |
224 |
|
|
225 |
/** |
/** |
226 |
* Returns true if this Set contains the supplied Object, |
* Returns true if this Set contains the supplied Object, false otherwise. |
|
* false otherwise |
|
227 |
* |
* |
228 |
* @param oObject the Object whose existence in the Set is |
* @param obj the Object to check for |
229 |
* being tested |
* @return true if it is in the set |
230 |
|
* @throws ClassCastException if obj cannot be compared with objects |
231 |
|
* already in the set |
232 |
*/ |
*/ |
233 |
public boolean contains(Object obj) |
public boolean contains(Object obj) |
234 |
{ |
{ |
235 |
return map.containsKey(obj); |
return map.containsKey(obj); |
236 |
} |
} |
237 |
|
|
238 |
/** Returns true if this Set has size 0, false otherwise */ |
/** |
239 |
public boolean isEmpty() |
* Returns the first (by order) element in this Set. |
240 |
|
* |
241 |
|
* @return the first element |
242 |
|
* @throws NoSuchElementException if the set is empty |
243 |
|
*/ |
244 |
|
public Object first() |
245 |
{ |
{ |
246 |
return map.isEmpty(); |
return map.firstKey(); |
247 |
} |
} |
248 |
|
|
249 |
/** Returns the number of elements in this Set */ |
/** |
250 |
public int size() |
* Returns a view of this Set including all elements less than |
251 |
|
* <code>to</code>. The returned set is backed by the original, so changes |
252 |
|
* in one appear in the other. The subset will throw an |
253 |
|
* {@link IllegalArgumentException} for any attempt to access or add an |
254 |
|
* element beyond the specified cutoff. The returned set does not include |
255 |
|
* the endpoint; if you want inclusion, pass the successor element. |
256 |
|
* |
257 |
|
* @param to the (exclusive) cutoff point |
258 |
|
* @return a view of the set less than the cutoff |
259 |
|
* @throws ClassCastException if <code>to</code> is not compatible with |
260 |
|
* the comparator (or is not Comparable, for natural ordering) |
261 |
|
* @throws NullPointerException if to is null, but the comparator does not |
262 |
|
* tolerate null elements |
263 |
|
*/ |
264 |
|
public SortedSet headSet(Object to) |
265 |
{ |
{ |
266 |
return map.size(); |
return new TreeSet(map.headMap(to)); |
267 |
} |
} |
268 |
|
|
269 |
/** |
/** |
270 |
* If the supplied Object is in this Set, it is removed, and true is |
* Returns true if this Set has size 0, false otherwise. |
|
* returned; otherwise, false is returned. |
|
271 |
* |
* |
272 |
* @param obj the Object we are attempting to remove |
* @return true if the set is empty |
|
* from this Set |
|
273 |
*/ |
*/ |
274 |
public boolean remove(Object obj) |
public boolean isEmpty() |
275 |
{ |
{ |
276 |
return (map.remove(obj) != null); |
return map.isEmpty(); |
277 |
} |
} |
278 |
|
|
279 |
/** Returns the first (by order) element in this Set */ |
/** |
280 |
public Object first() |
* Returns in Iterator over the elements in this TreeSet, which traverses |
281 |
|
* in ascending order. |
282 |
|
* |
283 |
|
* @return an iterator |
284 |
|
*/ |
285 |
|
public Iterator iterator() |
286 |
{ |
{ |
287 |
return map.firstKey(); |
return map.keySet().iterator(); |
288 |
} |
} |
289 |
|
|
290 |
/** Returns the last (by order) element in this Set */ |
/** |
291 |
|
* Returns the last (by order) element in this Set. |
292 |
|
* |
293 |
|
* @return the last element |
294 |
|
* @throws NoSuchElementException if the set is empty |
295 |
|
*/ |
296 |
public Object last() |
public Object last() |
297 |
{ |
{ |
298 |
return map.lastKey(); |
return map.lastKey(); |
299 |
} |
} |
300 |
|
|
301 |
/** |
/** |
302 |
* Returns a view of this Set including all elements in the interval |
* If the supplied Object is in this Set, it is removed, and true is |
303 |
* [oFromElement, oToElement). |
* returned; otherwise, false is returned. |
304 |
* |
* |
305 |
* @param from the resultant view will contain all |
* @param obj the Object to remove from this Set |
306 |
* elements greater than or equal to this element |
* @return true if the set was modified |
307 |
* @param to the resultant view will contain all |
* @throws ClassCastException if obj cannot be compared to set elements |
|
* elements less than this element |
|
308 |
*/ |
*/ |
309 |
public SortedSet subSet(Object from, Object to) |
public boolean remove(Object obj) |
310 |
{ |
{ |
311 |
return new TreeSet(map.subMap(from, to)); |
return map.remove(obj) != null; |
312 |
} |
} |
313 |
|
|
314 |
/** |
/** |
315 |
* Returns a view of this Set including all elements less than oToElement |
* Returns the number of elements in this Set |
316 |
* |
* |
317 |
* @param toElement the resultant view will contain all |
* @return the set size |
|
* elements less than this element |
|
318 |
*/ |
*/ |
319 |
public SortedSet headSet(Object to) |
public int size() |
320 |
{ |
{ |
321 |
return new TreeSet(map.headMap(to)); |
return map.size(); |
322 |
} |
} |
323 |
|
|
324 |
/** |
/** |
325 |
* Returns a view of this Set including all elements greater than or |
* Returns a view of this Set including all elements greater or equal to |
326 |
* equal to oFromElement. |
* <code>from</code> and less than <code>to</code> (a half-open interval). |
327 |
* |
* The returned set is backed by the original, so changes in one appear in |
328 |
* @param from the resultant view will contain all |
* the other. The subset will throw an {@link IllegalArgumentException} |
329 |
* elements greater than or equal to this element |
* for any attempt to access or add an element beyond the specified cutoffs. |
330 |
|
* The returned set includes the low endpoint but not the high; if you want |
331 |
|
* to reverse this behavior on either end, pass in the successor element. |
332 |
|
* |
333 |
|
* @param from the (inclusive) low cutoff point |
334 |
|
* @param to the (exclusive) high cutoff point |
335 |
|
* @return a view of the set between the cutoffs |
336 |
|
* @throws ClassCastException if either cutoff is not compatible with |
337 |
|
* the comparator (or is not Comparable, for natural ordering) |
338 |
|
* @throws NullPointerException if from or to is null, but the comparator |
339 |
|
* does not tolerate null elements |
340 |
|
* @throws IllegalArgumentException if from is greater than to |
341 |
*/ |
*/ |
342 |
public SortedSet tailSet(Object from) |
public SortedSet subSet(Object from, Object to) |
343 |
{ |
{ |
344 |
return new TreeSet(map.tailMap(from)); |
return new TreeSet(map.subMap(from, to)); |
345 |
} |
} |
346 |
|
|
347 |
/** Returns in Iterator over the elements in this TreeSet */ |
/** |
348 |
public Iterator iterator() |
* Returns a view of this Set including all elements greater or equal to |
349 |
|
* <code>from</code>. The returned set is backed by the original, so |
350 |
|
* changes in one appear in the other. The subset will throw an |
351 |
|
* {@link IllegalArgumentException} for any attempt to access or add an |
352 |
|
* element beyond the specified cutoff. The returned set includes the |
353 |
|
* endpoint; if you want to exclude it, pass in the successor element. |
354 |
|
* |
355 |
|
* @param from the (inclusive) low cutoff point |
356 |
|
* @return a view of the set above the cutoff |
357 |
|
* @throws ClassCastException if <code>from</code> is not compatible with |
358 |
|
* the comparator (or is not Comparable, for natural ordering) |
359 |
|
* @throws NullPointerException if from is null, but the comparator |
360 |
|
* does not tolerate null elements |
361 |
|
*/ |
362 |
|
public SortedSet tailSet(Object from) |
363 |
{ |
{ |
364 |
return map.keySet().iterator(); |
return new TreeSet(map.tailMap(from)); |
365 |
} |
} |
366 |
|
|
367 |
private void writeObject(ObjectOutputStream out) throws IOException |
/** |
368 |
|
* Serializes this object to the given stream. |
369 |
|
* |
370 |
|
* @param s the stream to write to |
371 |
|
* @throws IOException if the underlying stream fails |
372 |
|
* @serialData the <i>comparator</i> (Object), followed by the set size |
373 |
|
* (int), the the elements in sorted order (Object) |
374 |
|
*/ |
375 |
|
private void writeObject(ObjectOutputStream s) throws IOException |
376 |
{ |
{ |
377 |
|
s.defaultWriteObject(); |
378 |
Iterator itr = map.keySet().iterator(); |
Iterator itr = map.keySet().iterator(); |
379 |
int size = map.size(); |
int pos = map.size(); |
380 |
|
s.writeObject(map.comparator()); |
381 |
out.writeObject(map.comparator()); |
s.writeInt(pos); |
382 |
out.writeInt(size); |
while (--pos >= 0) |
383 |
|
s.writeObject(itr.next()); |
|
for (int i = 0; i < size; i++) |
|
|
out.writeObject(itr.next()); |
|
384 |
} |
} |
385 |
|
|
386 |
private void readObject(ObjectInputStream in) |
/** |
387 |
|
* Deserializes this object from the given stream. |
388 |
|
* |
389 |
|
* @param s the stream to read from |
390 |
|
* @throws ClassNotFoundException if the underlying stream fails |
391 |
|
* @throws IOException if the underlying stream fails |
392 |
|
* @serialData the <i>comparator</i> (Object), followed by the set size |
393 |
|
* (int), the the elements in sorted order (Object) |
394 |
|
*/ |
395 |
|
private void readObject(ObjectInputStream s) |
396 |
throws IOException, ClassNotFoundException |
throws IOException, ClassNotFoundException |
397 |
{ |
{ |
398 |
Comparator comparator = (Comparator) in.readObject(); |
s.defaultReadObject(); |
399 |
int size = in.readInt(); |
Comparator comparator = (Comparator) s.readObject(); |
400 |
TreeMap map = new TreeMap(comparator); |
int size = s.readInt(); |
401 |
map.putFromObjStream(in, size, false); |
map = new TreeMap(comparator); |
402 |
this.map = map; |
((TreeMap) map).putFromObjStream(s, size, false); |
403 |
} |
} |
404 |
} |
} |