tShuffle实现更改!
目录
传统的打乱list算法和本地算法比较
1.大多数时候大家一般是调用jdk原生提供方法Collections.shuffle(), 就可以轻松实现打乱list。
2.传统上打乱算法类似洗牌,理论上洗牌是有可能出现顺序不变的情况!Collections.shuffle()极端的情况下,是可能顺序不变的。
3.本次方法不是传统意义上的打乱,会保证至少交换一次顺序!基于trove4j的TintArrayList实现,应用时注意自己的业务需求!
1.jdk原生Collections.shuffle()
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();
//假设rnd.nextInt(i)极端情况每次随机都随到i - 1下标,那么就会导致顺序不变
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]);
}
}
}
Collections.shuffle()方法极端的情况下,是可能顺序不变的。
2.trove4j的TintArrayList打乱顺序,保证至少交换一次,从而保证一定是乱序
/**
* 打乱list顺序
* @param srcList
* @return
*/
public static TIntArrayList tShuffle(TIntArrayList srcList)
{
if (null == srcList)
{
return null;
}
//如果小于1,直接new一个新list返回,防止修改外部源
int size = srcList.size();
if (size <= 1)
{
return new TIntArrayList(srcList);
}
ThreadLocalRandom random = ThreadLocalRandom.current();
int[] objects = srcList.toArray();
for (int i = objects.length; i > 1; i--)
{
//random.nextInt(i - 1))从i - 1开始,那么至少保证交换一次
swap(objects, i-1, random.nextInt(i - 1));
}
//直接new一个新list返回,防止修改外部源
TIntArrayList list = new TIntArrayList(size);
for (int i = 0; i < size; i++)
{
list.add(objects[i]);
}
return list;
}
/**
* Swaps the two specified elements in the specified array.
*/
private static void swap(int[] arr, int i, int j)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
random.nextInt(i - 1))从i - 1开始,那么可以至少保证交换一次。
该方法是为了符合我们业务需求定制的,不是最高效的,应用时注意自己的业务需求!