AbstractCollection.removeAll(Collection) and AbstractSet.removeAll(Collection)

Rémi Forax forax at univ-mlv.fr
Wed Jul 13 16:27:48 UTC 2011


It doesn't work because the complexity of size() can be O(n).
In my opinion, only the checks for emptyness are Ok.

Rémi


On 07/13/2011 05:40 PM, Sebastian Sickelmann wrote:
> Jeff Hain wrote:
>> Hello.
>>   
>> I have some remarks about the methods named in the subject (JDK 6u26, JDK
>> 7b147).
>>   
>>   
>> 1) AbstractCollection.removeAll(Collection)
>>     This method could return immediately if the specified collection is
>> empty,
>> not to iterate uselessly over all "this", or if "this" is empty, not to
>> create
>> an
>> iterator for nothing.public boolean removeAll(Collection<?>  c) {
>>     boolean modified = false;
>>     if (size()>  c.size()) {
>>        for (Iterator<?>  i = c.iterator(); i.hasNext(); )
>>           modified |= remove(i.next());
>>     } else {
>>        for (Iterator<?>  i = iterator(); i.hasNext(); ) {
>>           if (c.contains(i.next())) {
>>              i.remove();
>>              modified = true;
>>           }
>>        }
>>     }
>>     return modified;
>> }
>>   
>> # Alternative implementation (not tested):public boolean
>> removeAll(Collection<?>
>> c) {
>>     // Quick check on emptinesses, to make later treatments simpler.
>>     if (isEmpty() || c.isEmpty()) {
>>        return false;
>>     }
>>     boolean modified = false;
>>     final int n1 = size();
>>     final int n2 = c.size();
>>     // If the "c" is not a set, we are pessimistic about its "contains"
>> method
>> complexity.
>>     final int cContainsAssumedComplexity = (c instanceof Set<?>) ? 1 :
>> n2;
>>     // If we iterate over "this", assumed complexity is O(n2).
>>     // If we iterate over "c", assumed complexity is O(n1 *
>> cContainsAssumedComplexity).
>>     // Cast to long to avoid overflow.
>>     if (n2<  n1 * (long)cContainsAssumedComplexity) {
>>        for (Iterator<?>  i = c.iterator(); i.hasNext(); ) {
>>           if (remove(i.next())) {
>>              modified = true;
>>              if (isEmpty()) {
>>                 break;
>>              }
>>           }
>>        }
>>     } else {
>>        for (Iterator<?>  i = iterator(); i.hasNext(); ) {
>>           if (c.contains(i.next())) {
>>              i.remove();
>>              modified = true;
>>           }
>>        }
>>     }
>>     return modified;
>> }
> look good to me.
>
>>     I also thought about returning as soon as as many elements as the
>> specified
>> collection
>> contains have been removed, but it would not behave properly with
>> collections
>> containing
>> more than Integer.MAX_VALUE elements, or with some overriden equals
>> methods etc.
> The overriden equals method should be no problem if the Implementation is an set. So it should be possible to exit in this case in the AbstractSet Implementation, isn't it?
>
>>   
>>   
>> 2) AbstractSet.removeAll(Collection)
>>     Let n1 be the size of "this", and n2 the size of the specified
>> collection.
>>     This method is in O(n1*n2) if the specified collection has a
>> contains(Object)
>> method in O(n2)
>> (as an ArrayList does), and n1<= n2.
>>     I think a better implementation could be done by taking care of the
>> "setness"
>> of the specified collection,
>> and taking care of collections sizes differently.
>>     Also:
>> - when iterating on the specified collection, the method could return as
>> soon
>> as "this" is empty,
>>    not to continue useless iterations.
>> - when iterating on "this", the method could return if the specified
>> collection
>> is empty,
>>    not to iterate over all "this" uselessly.
>>   
>> # Current implementation:
>>
>>
>> Regards,
>>
>> Jeff
>>




More information about the core-libs-dev mailing list