2

I suspect it doesn't. If I want to use the fact that the list is ordered, should I implement my own contains() method, using binary search, for example? Are there any methods that assume that the list is ordered?

This question is different to the possible duplicate because the other question doesn't ask about the contains() method.

SHR
  • 7,940
  • 9
  • 38
  • 57
Guillermo Mosse
  • 462
  • 2
  • 14
  • 7
    [`Collections.binarySearch(...)`](https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#binarySearch(java.util.List,%20T)) – khelwood Jul 05 '18 at 07:54
  • 1
    `List.contains` use `indexOf` to find an occurrence and since `indexOf` return the first element, it will iterate normally the list. It won't be faster since it will still iterate from start to end. – AxelH Jul 05 '18 at 07:55
  • 1
    You should limit your question to ONE question, or perhaps another question more detailling what you mean. The topic of your question is now "does it work faster if ordered?" - The answer is no (will post it soon). The other questions should be moved to an extra question "how to implement a contains method in a runtime efficient way?" (but that will most probably already exist) – Florian Albrecht Jul 05 '18 at 07:57
  • Possible duplicate of [Binary search in an ordered list in java](https://stackoverflow.com/questions/18110619/binary-search-in-an-ordered-list-in-java) – AxelH Jul 05 '18 at 07:58

5 Answers5

3

No, because ArrayList is backed by array and internally calls indexOf(Object o) method where it searches sequentially. Thus sorting is not relevant to it. Here's the source code:

/**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
Shubhendu Pramanik
  • 2,711
  • 2
  • 13
  • 23
  • I don't see why the `array` is a problem (binary search is still possible) but the rest is correct. – AxelH Jul 05 '18 at 07:59
  • @Alex array is not problem for binary searching because there you need sorted array and you don't access array there sequentially but directly. – Shubhendu Pramanik Jul 05 '18 at 08:03
2

Use binary search of collections to search in an ordered array list

Collections.<T>binarySearch(List<T> list, T key)

Arraylist.contains will consider this as a normal list and it would take the same amount of time as any unordered list that is O(n) whereas complexity of binary search would be O(logn) in worst case

Suhaib Roomy
  • 2,501
  • 1
  • 16
  • 22
2

No. contains uses indexOf:

public boolean contains(Object var1) {
    return this.indexOf(var1) >= 0;
}

and indexOf just simply iterates over the internal array:

for(var2 = 0; var2 < this.size; ++var2) {
    if (var1.equals(this.elementData[var2])) {
        return var2;
    }
}

Collections.binarySearch is what you're looking for:

Searches the specified list for the specified object using the binary search algorithm. The list must be sorted into ascending order according to the natural ordering of its elements (as by the sort(List) method) prior to making this call. If it is not sorted, the results are undefined.

Emphasis mine

Also consider using a SortedSet such as a TreeSet which will provide stronger guarantees that the elements are kept in the correct order, unlike a List which must rely on caller contracts (as highlighted above)

Michael
  • 41,989
  • 11
  • 82
  • 128
1

Does the ArrayList's contains() method work faster if the ArrayList is ordered?

It doesn't. The implementation of ArrayList does not know if the list is ordered or not. Since it doesn't know, it cannot optimize in the case when it is ordered. (And an examination of the source code bears this out.)

Could a (hypothetical) array-based-list implementation know? I think "No" for the following reasons:

  1. Without either a Comparator or a requirement that elements implement Comparable, the concept of ordering is ill-defined.

  2. The cost of checking that a list is ordered is O(N). The cost of incrementally checking that a list is still ordered is O(1) ... but still one or two calls to compare on each update operation. That is a significant overhead ... for a general purpose data structure to incur in the hope of optimizing (just) one operation in the API.

But that's OK. If you (the programmer) are able to ensure (ideally by efficient algorithmic means) that a list is always ordered, then you can use Collections.binarySearch ... with zero additional checking overhead in update operations.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

Just to keep it simple.

If you have an array [5,4,3,2,1] and you order it to [1,2,3,4,5] will forks faster if you look for 1 but it will take longer to find 5. Consequently, from the mathematical point of view if you order an array, searching for an item inside will anyway require to loop from 1 to, in the worst case, n.

May be that for your problem sorting may help, say you receive unordered timestamps but

  1. if your array is not too small
  2. want to avoid the additional cost of sorting per each new entry in the array
  3. you just want to find quickly an object
  4. you know the Object properties you are searching for

you can create a KeyObject containing the properties you are looking for implements equals & hashCode for it then store your items into a Map. Using a Map.containsKey(new KeyObject(prop1, prop2)) would be in any case faster than looping the array. If you do not have the real object you can always create a fake KeyObject, filled with the properties you expect, to check the Map.

user2688838
  • 761
  • 5
  • 11