简体   繁体   中英

Which Java collection allows fastest element removal?

I'm looking for a collection that allows fastest element removal. I tested ArrayList on 1 million rows and it turns out removing the first element is faster than removing the last one. It takes about 50 seconds to remove one million elements

import java.util.ArrayList;

public class TestArray {

    final int numberOfElements = 1000000; 

    public void testArray () { 

    // test array 
    ArrayList<String> testArray = new ArrayList<String>(); 
    for (int i = 0; i < numberOfElements; i++) { 
        testArray.add("" + Math.random()); 
    }

    // testing speed when removing the first element  
    long startTime = System.currentTimeMillis(); 
    while (true) { 
        if (testArray.isEmpty()) { 
            System.out.println("Milliseconds to fisnish when removing the first element " + (System.currentTimeMillis() - startTime));
            break; 
        } 
        else { 
            String testString = testArray.get(0); 
            testArray.remove(testString); 
        }
    } 

    testArray = new ArrayList<String>(); 
    for (int i = 0; i < numberOfElements; i++) { 
        testArray.add("" + Math.random()); 
    } 
    // testing speed when removing the last   element  
        long startTime2 = System.currentTimeMillis(); 
        while (true) { 
            if (testArray.isEmpty()) { 
                System.out.println("Milliseconds to fisnish when removing the last element " + (System.currentTimeMillis() - startTime2));
                break; 
            } 
            else { 
                String testString = testArray.get(testArray.size()-1); 
                testArray.remove(testString); 
            }
        }



    } 

}

But I'm not sure if this is the fastest possible way. Is 50 seconds the fastest way? Or is there any better collection, for example will LinkedList do it faster? Or what is the fastest collection to remove elements one by one?

1) You should consider LinkedList which has O(1) Big O performance for remove operation (Explanation below) , while ArrayList is O(n).
2) You can try HashSet if you are not interested in duplicates.

LinkedList Remove:

1) LinkedList removal at the beginning and end is constant time since traversal is not required.

2) It takes longer time for removing the middle elements because the element needs to be found first.

3) If you have an iterator at the location you want to remove, then remove is constant time.

The best collection for performance is TreeSet because if you insert objects in according to Comparable / Comparator, collection will be orded.

My times: ArrayList Milliseconds to fisnish when removing the first element 698 Milliseconds to fisnish when removing the last element 121960

TreeSet: Milliseconds to fisnish when removing the first element 55 Milliseconds to fisnish when removing the last element 50

WARNING: With this solutions you can't have duplicate objects in the collection.

@Test
    public void testTreeSet() {
        /* RESULTS
         * Milliseconds to fisnish when removing the first element 55
         * Milliseconds to fisnish when removing the last element 50
         */

        // test array
        TreeSet<String> testArray = new TreeSet<String>();
        int numberOfElements = 100000;
        for (int i = 0; i < numberOfElements; i++) {
            testArray.add("" + Math.random());
        }

        // testing speed when removing the first element
        long startTime = System.currentTimeMillis();
        while (true) {
            if (testArray.isEmpty()) {
                System.out.println("Milliseconds to fisnish when removing the first element "
                        + (System.currentTimeMillis() - startTime));
                break;
            } else {
                //String testString = testArray.get(0);
                String testString = testArray.first();
                testArray.remove(testString);
            }
        }

        testArray = new TreeSet<String>();
        for (int i = 0; i < numberOfElements; i++) {
            testArray.add("" + Math.random());
        }
        // testing speed when removing the last element
        long startTime2 = System.currentTimeMillis();
        while (true) {
            if (testArray.isEmpty()) {
                System.out.println("Milliseconds to fisnish when removing the last element "
                        + (System.currentTimeMillis() - startTime2));
                break;
            } else {
                //String testString = testArray.get(testArray.size() - 1);
                String testString = testArray.last();
                testArray.remove(testString);
            }
        }

    }

First: There must be something wrong with your benchmark, a ArrayList removes elements much slower then adding some. This is because the array must not have gaps in the underlaying array. So elements need to be shifted if you remove everywhere but in the end.

This answer depends wether you want to remove index-based or value-based. In general, index-based operations are faster because no expansive value comparisons need to be made. Since if you want to remove elements you must have added them once, it is helpful to consider the add complexity as well

  • ArrayList: Add: O(n), amortized O(1) (in practice cheap). Remove is always O(n), Find O(1) if index-based, O(n) if value based

Example in practice for the effect of amortized analysis: Adding one million elements in a row will result in 10 million copies. However the number of copies is O(log n), n is the number of consecutive add operations.

  • LinkedList Add: O(n) at average, AddFirst/Last O(1), removeLast/First O(1), find O(n), getFirstElement/GetLastElement O(1). Note here: You have to know, that the element you search for is in the end/beginning and call the corresponding method.

So far, if you have a lot of consecutive add/remove operations and few search operations (except getting the first or last element), I recommend you to use LinkedList .

If you have no two identical objects, that is ( Object.equals(sameObject) ) returns true for exactly the same object. you should use LinkedHashSet It has O(1) for all operations, but equal objects can only be contained once. Unfortunately index-based search is here not possible, the methods are also not snychronized. But there is always a trade-off.

Some theory: According to the papers mentioned here we cannot do better then amortized Omega(log n) for arbitraty adding and removal of elements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM