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]); } } }
若是list的size小於SHUFFLE_THRESHOLD(5) 或者 list實現了RandomAccess接口,則直接交換list內元素的位置。具體的交換策略以下:數組
令list的size爲n, 從n-1位開始,將該位的元素與其前面某一位(隨機獲得)元素交換,直到第1位結束。
使用的函數:數據結構
public static void swap(List<?> list, int i, int j) { // 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 final List l = list; l.set(i, l.set(j, l.get(i))); //將j位置的值和i位置的值進行交換 }
/** * Replaces the element at the specified position in this list with the * specified element (optional operation). * * @param index index of the element to replace * @param element element to be stored at the specified position */ E set(int index, E element)
public E set(int index, E element) { try { ListIterator<E> e = listIterator(index); E oldVal = e.next(); e.set(element); return oldVal; //將index的值設置爲element,並返回原來的值 } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("Index: "+index); } }
這時候首先要作的是將list轉化成數組,這個和RandomAccess有關app
/** * Marker interface used by <tt>List</tt> implementations to indicate that * they support fast (generally constant time) random access. The primary * purpose of this interface is to allow generic algorithms to alter their * behavior to provide good performance when applied to either random or * sequential access lists. * * <p>The best algorithms for manipulating random access lists (such as * <tt>ArrayList</tt>) can produce quadratic behavior when applied to * sequential access lists (such as <tt>LinkedList</tt>). Generic list * algorithms are encouraged to check whether the given list is an * <tt>instanceof</tt> this interface before applying an algorithm that would * provide poor performance if it were applied to a sequential access list, * and to alter their behavior if necessary to guarantee acceptable * performance. * ...... public interface RandomAccess { }
RandomAccess用於標識ist的實現類是否支持快速地隨機訪問(通常是O(1)的時間複雜度),例如ArraryList實現了RandomAccess接口,隨機訪問一個元素(get(i))所花費的時間複雜度是O(1),而LinkedList卻沒有實現這個接口,因此隨機一個元素的時間複雜度是O(n)(最壞狀況)。因此在遍歷一個list時,能夠先判斷它是否實現了RandomAccess接口,根據數據結構的不一樣先進行相應的處理,避免出現O(n2)的時間複雜度。
如在shuffle()的else代碼段中,就先將沒有實現RandomAccess接口的list轉換成數組,而後在執行交換策略,這樣避免O(n2)的時間複雜度。dom
以上內容若有不正確的地方,歡迎支持。ide