[Java] Implementation of shuffling effect Model and RandomAccess interface

The implementation of the shuffle effect is not complicated, and the static method shuffle(List<?> list) of Collections is mainly used:

List list = new LinkedList();
list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
Collections.shuffle(list);//list will be shuffled
list.forEach(System.out::println);
The internal implementation of shuffle is mainly based on the swap method:

public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextInt(i));
        } else {
            Object arr[] = list.toArray();

            // Shuffle array
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));

            // Dump array back into list
            // instead of using a raw type here, it's possible to capture
            // the wildcard but it will require a call to a supplementary
            // private method
            ListIterator it = list.listIterator ();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }
Its complexity is linear . In order to improve efficiency and avoid increasing the complexity to the square level (the iterative method of some classes is a square level or higher than the access form such as the for statement) , when the size of the List is too large (the default threshold is 5) and it is not a RandomAccess When the interface is implemented, the list will be converted to an Object[], and the following swap method will be executed:

    private static void swap(Object[] arr, int i, int j) {
        Object tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
It is easy to see that this is the most common swap algorithm. After this swap is performed, the Objcet[] is converted to a list through the iterator.

Otherwise, the swap method of Collection will be called directly through for(i=list.size();i>=0;i--):

    public static void swap(List<?> list, int i, int j) {
        final List l = list;
        l.set(i, l.set(j, l.get(i)));
    }


Here comes a question: why do it ?

We need to understand the RandomAccess interface. This is a marker interface, and its internal methods are empty, which can be understood as an annotation on the class marker, which is used to indicate a certain feature of this class, which is an atypical usage of the interface.


RandomAccess is not "random access" in the full sense, it is relative to the "sequential access" of iterators . Its "random access" actually represents a feature of the class: it is not the most efficient method to traverse the class with an iterator. I hope programmers can consider using for(i=0;i<size;i++) method to access the class.


When the custom access method of a class is faster than using iterator access, then this marker interface should be marked to inform other programs of the correct choice for accessing and traversing the collection - for example, for(i=0;i<list .size();i++) or for(i=list.size();i>=0;i--), any other "access order" is faster than using while(Iterator().next()), The RandomAccess marker interface can then be marked. Obviously for(i=0;i<list.size();i++) is literally "sequential access", but that doesn't prevent it from being called "RandomAccess".



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325644768&siteId=291194637