数组的随机洗牌

我需要随机洗牌以下数组:

int[] solutionArray = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1};

有什么函数可以做到吗?

523504 次浏览

看看Collections类,特别是shuffle(...)类。

使用集合来洗牌一个基本类型数组有点过分……

自己实现这个函数很简单,例如使用Fisher-Yates洗牌:

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;


class Test
{
public static void main(String args[])
{
int[] solutionArray = { 1, 2, 3, 4, 5, 6, 16, 15, 14, 13, 12, 11 };


shuffleArray(solutionArray);
for (int i = 0; i < solutionArray.length; i++)
{
System.out.print(solutionArray[i] + " ");
}
System.out.println();
}


// Implementing Fisher–Yates shuffle
static void shuffleArray(int[] ar)
{
// If running on Java 6 or older, use `new Random()` on RHS here
Random rnd = ThreadLocalRandom.current();
for (int i = ar.length - 1; i > 0; i--)
{
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
}

下面是使用ArrayList的简单方法:

List<Integer> solution = new ArrayList<>();
for (int i = 1; i <= 6; i++) {
solution.add(i);
}
Collections.shuffle(solution);

下面是一个有效的Fisher-Yates shuffle数组函数:

private static void shuffleArray(int[] array)
{
int index;
Random random = new Random();
for (int i = array.length - 1; i > 0; i--)
{
index = random.nextInt(i + 1);
if (index != i)
{
array[index] ^= array[i];
array[i] ^= array[index];
array[index] ^= array[i];
}
}
}

private static void shuffleArray(int[] array)
{
int index, temp;
Random random = new Random();
for (int i = array.length - 1; i > 0; i--)
{
index = random.nextInt(i + 1);
temp = array[index];
array[index] = array[i];
array[i] = temp;
}
}

集合类有一个有效的洗牌方法,可以被复制,从而不依赖于它:

/**
* Usage:
*    int[] array = {1, 2, 3};
*    Util.shuffle(array);
*/
public class Util {


private static Random random;


/**
* Code from method java.util.Collections.shuffle();
*/
public static void shuffle(int[] array) {
if (random == null) random = new Random();
int count = array.length;
for (int i = count; i > 1; i--) {
swap(array, i - 1, random.nextInt(i));
}
}


private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}

使用ArrayList<Integer>可以帮助你解决洗牌的问题,而不应用太多的逻辑和消耗更少的时间。以下是我的建议:

ArrayList<Integer> x = new ArrayList<Integer>();
for(int i=1; i<=add.length(); i++)
{
x.add(i);
}
Collections.shuffle(x);

下面是使用Collections.shuffle方法的完整解决方案:

public static void shuffleArray(int[] array) {
List<Integer> list = new ArrayList<>();
for (int i : array) {
list.add(i);
}


Collections.shuffle(list);


for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
}

请注意,由于Java无法在int[]Integer[](以及int[]List<Integer>)之间顺利转换,所以它会受到影响。

下面是数组的泛型版本:

import java.util.Random;


public class Shuffle<T> {


private final Random rnd;


public Shuffle() {
rnd = new Random();
}


/**
* Fisher–Yates shuffle.
*/
public void shuffle(T[] ar) {
for (int i = ar.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
T a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
}

考虑到ArrayList基本上只是一个数组,使用ArrayList而不是显式数组并使用Collections.shuffle()可能是明智的。但是,性能测试并没有显示上述方法与Collections.sort()之间有任何显著差异:

Shuffe<Integer>.shuffle(...) performance: 576084 shuffles per second
Collections.shuffle(ArrayList<Integer>) performance: 629400 shuffles per second
MathArrays.shuffle(int[]) performance: 53062 shuffles per second

Apache Commons实现MathArrays。Shuffle限制为int[],性能损失可能是由于使用了随机数生成器。

Random rnd = new Random();
for (int i = ar.length - 1; i > 0; i--)
{
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}

顺便说一下,我注意到这段代码返回ar.length - 1的元素数量,所以如果你的数组有5个元素,新的打乱的数组将有4个元素。发生这种情况是因为for循环说i>0。如果更改为i>=0,则所有元素都被打乱。

你有几个选择。当涉及到洗牌时,列表与数组有点不同。

如下所示,数组比列表快,而基元数组比对象数组快。

样品时间

List<Integer> Shuffle: 43133ns
Integer[] Shuffle: 31884ns
int[] Shuffle: 25377ns

下面是shuffle的三种不同实现。您应该只使用集合。如果处理的是集合,则Shuffle。没有必要为了排序而将数组包装到一个集合中。下面的方法实现起来非常简单。

ShuffleUtil类

import java.lang.reflect.Array;
import java.util.*;


public class ShuffleUtil<T> {
private static final int[] EMPTY_INT_ARRAY = new int[0];
private static final int SHUFFLE_THRESHOLD = 5;


private static Random rand;

主要方法

    public static void main(String[] args) {
List<Integer> list = null;
Integer[] arr = null;
int[] iarr = null;


long start = 0;
int cycles = 1000;
int n = 1000;


// Shuffle List<Integer>
start = System.nanoTime();
list = range(n);
for (int i = 0; i < cycles; i++) {
ShuffleUtil.shuffle(list);
}
System.out.printf("%22s: %dns%n", "List<Integer> Shuffle", (System.nanoTime() - start) / cycles);


// Shuffle Integer[]
start = System.nanoTime();
arr = toArray(list);
for (int i = 0; i < cycles; i++) {
ShuffleUtil.shuffle(arr);
}
System.out.printf("%22s: %dns%n", "Integer[] Shuffle", (System.nanoTime() - start) / cycles);


// Shuffle int[]
start = System.nanoTime();
iarr = toPrimitive(arr);
for (int i = 0; i < cycles; i++) {
ShuffleUtil.shuffle(iarr);
}
System.out.printf("%22s: %dns%n", "int[] Shuffle", (System.nanoTime() - start) / cycles);
}

变换通用列表

    // ================================================================
// Shuffle List<T> (java.lang.Collections)
// ================================================================
@SuppressWarnings("unchecked")
public static <T> void shuffle(List<T> list) {
if (rand == null) {
rand = new Random();
}
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i = size; i > 1; i--) {
swap(list, i - 1, rand.nextInt(i));
}
} else {
Object arr[] = list.toArray();


for (int i = size; i > 1; i--) {
swap(arr, i - 1, rand.nextInt(i));
}


ListIterator<T> it = list.listIterator();
int i = 0;


while (it.hasNext()) {
it.next();
it.set((T) arr[i++]);
}
}
}


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


public static <T> List<T> shuffled(List<T> list) {
List<T> copy = copyList(list);
shuffle(copy);
return copy;
}

变换泛型数组

    // ================================================================
// Shuffle T[]
// ================================================================
public static <T> void shuffle(T[] arr) {
if (rand == null) {
rand = new Random();
}


for (int i = arr.length - 1; i > 0; i--) {
swap(arr, i, rand.nextInt(i + 1));
}
}


public static <T> void swap(T[] arr, int i, int j) {
T tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}


public static <T> T[] shuffled(T[] arr) {
T[] copy = Arrays.copyOf(arr, arr.length);
shuffle(copy);
return copy;
}

打乱原语数组

    // ================================================================
// Shuffle int[]
// ================================================================
public static <T> void shuffle(int[] arr) {
if (rand == null) {
rand = new Random();
}


for (int i = arr.length - 1; i > 0; i--) {
swap(arr, i, rand.nextInt(i + 1));
}
}


public static <T> void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}


public static int[] shuffled(int[] arr) {
int[] copy = Arrays.copyOf(arr, arr.length);
shuffle(copy);
return copy;
}

实用方法

简单的实用工具方法复制和转换数组到列表,反之亦然。

    // ================================================================
// Utility methods
// ================================================================
protected static <T> List<T> copyList(List<T> list) {
List<T> copy = new ArrayList<T>(list.size());
for (T item : list) {
copy.add(item);
}
return copy;
}


protected static int[] toPrimitive(Integer[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_INT_ARRAY;
}
final int[] result = new int[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i].intValue();
}
return result;
}


protected static Integer[] toArray(List<Integer> list) {
return toArray(list, Integer.class);
}


protected static <T> T[] toArray(List<T> list, Class<T> clazz) {
@SuppressWarnings("unchecked")
final T[] arr = list.toArray((T[]) Array.newInstance(clazz, list.size()));
return arr;
}

范围类

生成一个值范围,类似于Python的range函数。

    // ================================================================
// Range class for generating a range of values.
// ================================================================
protected static List<Integer> range(int n) {
return toList(new Range(n), new ArrayList<Integer>());
}


protected static <T> List<T> toList(Iterable<T> iterable) {
return toList(iterable, new ArrayList<T>());
}


protected static <T> List<T> toList(Iterable<T> iterable, List<T> destination) {
addAll(destination, iterable.iterator());


return destination;
}


protected static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
while (iterator.hasNext()) {
collection.add(iterator.next());
}
}


private static class Range implements Iterable<Integer> {
private int start;
private int stop;
private int step;


private Range(int n) {
this(0, n, 1);
}


private Range(int start, int stop) {
this(start, stop, 1);
}


private Range(int start, int stop, int step) {
this.start = start;
this.stop = stop;
this.step = step;
}


@Override
public Iterator<Integer> iterator() {
final int min = start;
final int max = stop / step;


return new Iterator<Integer>() {
private int current = min;


@Override
public boolean hasNext() {
return current < max;
}


@Override
public Integer next() {
if (hasNext()) {
return current++ * step;
} else {
throw new NoSuchElementException("Range reached the end");
}
}


@Override
public void remove() {
throw new UnsupportedOperationException("Can't remove values from a Range");
}
};
}
}
}

你现在可以使用java 8了:

Collections.addAll(list, arr);
Collections.shuffle(list);
cardsList.toArray(arr);

我在权衡这个非常流行的问题,因为没有人写过一个shuffle-copy版本。Style大量借鉴了Arrays.java,因为谁不是掠夺Java技术这些天?包括泛型和int实现。

   /**
* Shuffles elements from {@code original} into a newly created array.
*
* @param original the original array
* @return the new, shuffled array
* @throws NullPointerException if {@code original == null}
*/
@SuppressWarnings("unchecked")
public static <T> T[] shuffledCopy(T[] original) {
int originalLength = original.length; // For exception priority compatibility.
Random random = new Random();
T[] result = (T[]) Array.newInstance(original.getClass().getComponentType(), originalLength);


for (int i = 0; i < originalLength; i++) {
int j = random.nextInt(i+1);
result[i] = result[j];
result[j] = original[i];
}


return result;
}




/**
* Shuffles elements from {@code original} into a newly created array.
*
* @param original the original array
* @return the new, shuffled array
* @throws NullPointerException if {@code original == null}
*/
public static int[] shuffledCopy(int[] original) {
int originalLength = original.length;
Random random = new Random();
int[] result = new int[originalLength];


for (int i = 0; i < originalLength; i++) {
int j = random.nextInt(i+1);
result[i] = result[j];
result[j] = original[i];
}


return result;
}

下面的代码将实现数组的随机排序。

// Shuffle the elements in the array
Collections.shuffle(Arrays.asList(array));

来自:http://www.programcreek.com/2012/02/java-method-to-shuffle-an-int-array-with-random-order/

这是knuth shuffle算法。

public class Knuth {


// this class should not be instantiated
private Knuth() { }


/**
* Rearranges an array of objects in uniformly random order
* (under the assumption that <tt>Math.random()</tt> generates independent
* and uniformly distributed numbers between 0 and 1).
* @param a the array to be shuffled
*/
public static void shuffle(Object[] a) {
int n = a.length;
for (int i = 0; i < n; i++) {
// choose index uniformly in [i, n-1]
int r = i + (int) (Math.random() * (n - i));
Object swap = a[r];
a[r] = a[i];
a[i] = swap;
}
}


/**
* Reads in a sequence of strings from standard input, shuffles
* them, and prints out the results.
*/
public static void main(String[] args) {


// read in the data
String[] a = StdIn.readAllStrings();


// shuffle the array
Knuth.shuffle(a);


// print results.
for (int i = 0; i < a.length; i++)
StdOut.println(a[i]);
}
}

下面是一个使用Apache Commons Math 3的解决方案。X(仅适用于int[]数组):

MathArrays.shuffle(array);

http://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/org/apache/commons/math3/util/MathArrays.html#shuffle(int[])

另外,Apache Commons Lang 3.6为ArrayUtils类引入了新的shuffle方法(用于对象和任何基本类型)。

ArrayUtils.shuffle(array);

http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/ArrayUtils.html#shuffle-int:A-

还有另一种方法,还没有发布

//that way, send many object types diferentes
public anotherWayToReciveParameter(Object... objects)
{
//ready with array
final int length =objects.length;
System.out.println(length);
//for ready same list
Arrays.asList(objects);
}

这种方法更简单,取决于上下文

最简单的解决方案,这种随机洗牌数组。

String location[] = {"delhi","banglore","mathura","lucknow","chandigarh","mumbai"};
int index;
String temp;
Random random = new Random();
for(int i=1;i<location.length;i++)
{
index = random.nextInt(i+1);
temp = location[index];
location[index] = location[i];
location[i] = temp;
System.out.println("Location Based On Random Values :"+location[i]);
}

我在一些答案中看到了一些遗漏的信息,所以我决定添加一个新的。

Java集合数组。asList接受类型为T (T ...)的变量参数。如果传递一个基元数组(int array), asList方法将推断并生成一个List<int[]>,这是一个单元素列表(其中一个元素是基元数组)。如果你洗牌这个元素列表,它不会改变任何东西。

首先,你需要将原始数组转换为Wrapper对象数组。为此,您可以使用apache.commons.lang中的ArrayUtils.toObject方法。然后将生成的数组传递给一个List,最后洗牌。

  int[] intArr = {1,2,3};
List<Integer> integerList = Arrays.asList(ArrayUtils.toObject(array));
Collections.shuffle(integerList);
//now! elements in integerList are shuffled!
public class ShuffleArray {
public static void shuffleArray(int[] a) {
int n = a.length;
Random random = new Random();
random.nextInt();
for (int i = 0; i < n; i++) {
int change = i + random.nextInt(n - i);
swap(a, i, change);
}
}


private static void swap(int[] a, int i, int change) {
int helper = a[i];
a[i] = a[change];
a[change] = helper;
}


public static void main(String[] args) {
int[] a = new int[] { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1 };
shuffleArray(a);
for (int i : a) {
System.out.println(i);
}
}
}

Groovy的一个简单解决方案:

solutionArray.sort{ new Random().nextInt() }

这将对数组列表中的所有元素进行随机排序,存档所有元素洗牌的预期结果。

  1. 盒子int[]List<Integer>
  2. 使用Collections.shuffle方法进行Shuffle
int[] solutionArray = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1 };


List<Integer> list = Arrays.stream(solutionArray).boxed().collect(Collectors.toList());
Collections.shuffle(list);


System.out.println(list.toString());
// [1, 5, 5, 4, 2, 6, 1, 3, 3, 4, 2, 6]

这是另一种洗牌的方法

public List<Integer> shuffleArray(List<Integer> a) {
List<Integer> b = new ArrayList<Integer>();
while (a.size() != 0) {
int arrayIndex = (int) (Math.random() * (a.size()));
b.add(a.get(arrayIndex));
a.remove(a.get(arrayIndex));
}
return b;
}

从原始列表中选择一个随机数,并将其保存在另一个列表中。然后从原始列表中删除该数字。原始列表的大小将继续减小1,直到所有元素都移动到新列表中。

最简单的洗牌代码:

import java.util.*;
public class ch {
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
ArrayList<Integer> l=new ArrayList<Integer>(10);
for(int i=0;i<10;i++)
l.add(sc.nextInt());
Collections.shuffle(l);
for(int j=0;j<10;j++)
System.out.println(l.get(j));
}
}
import java.util.ArrayList;
import java.util.Random;
public class shuffle {
public static void main(String[] args) {
int a[] =  {1,2,3,4,5,6,7,8,9};
ArrayList b = new ArrayList();
int i=0,q=0;
Random rand = new Random();


while(a.length!=b.size())
{
int l = rand.nextInt(a.length);
//this is one option to that but has a flaw on 0
//           if(a[l] !=0)
//           {
//                b.add(a[l]);
//               a[l]=0;
//
//           }
//
// this works for every no.
if(!(b.contains(a[l])))
{
b.add(a[l]);
}






}


//        for (int j = 0; j <b.size(); j++) {
//            System.out.println(b.get(j));
//
//        }
System.out.println(b);
}


}

类似的情况没有使用swap b

    Random r = new Random();
int n = solutionArray.length;
List<Integer> arr =  Arrays.stream(solutionArray)
.boxed()
.collect(Collectors.toList());
for (int i = 0; i < n-1; i++) {
solutionArray[i] = arr.remove(r.nextInt(arr.size())); // randomize based on size
}
solutionArray[n-1] = arr.get(0);

其中一种解决方法是使用排列来预先计算所有的排列并存储在数组列表中

Java 8在Java .util. random类中引入了一个新方法ints()。ints()方法返回无限的伪随机int值流。您可以通过提供最小值和最大值来限制指定范围内的随机数。

Random genRandom = new Random();
int num = genRandom.nextInt(arr.length);
在生成随机数的帮助下,您可以遍历循环并将当前索引与随机数交换。 这就是生成空间复杂度为O(1)的随机数的方法

使用Guava的Ints.asList()就像这样简单:

Collections.shuffle(Ints.asList(array));

无随机解:

   static void randomArrTimest(int[] some){
long startTime = System.currentTimeMillis();
for (int i = 0; i < some.length; i++) {
long indexToSwap = startTime%(i+1);
long tmp = some[(int) indexToSwap];
some[(int) indexToSwap] = some[i];
some[i] = (int) tmp;
}
System.out.println(Arrays.toString(some));
}

使用随机类

  public static void randomizeArray(int[] arr) {


Random rGenerator = new Random(); // Create an instance of the random class
for (int i =0; i< arr.length;i++ ) {
//Swap the positions...


int rPosition = rGenerator.nextInt(arr.length); // Generates an integer within the range (Any number from 0 - arr.length)
int temp = arr[i]; // variable temp saves the value of the current array index;
arr[i] = arr[rPosition];  // array at the current position (i) get the value of the random generated
arr[rPosition] = temp; // the array at the position of random generated gets the value of temp


}


for(int i = 0; i<arr.length; i++) {
System.out.print(arr[i]); //Prints out the array
}


}

你应该使用Collections.shuffle()。但是,不能直接操作原始类型数组,因此需要创建包装器类。

试试这个。

public static void shuffle(int[] array) {
Collections.shuffle(new AbstractList<Integer>() {
@Override public Integer get(int index) { return array[index]; }
@Override public int size() { return array.length; }
@Override public Integer set(int index, Integer element) {
int result = array[index];
array[index] = element;
return result;
}
});
}

int[] solutionArray = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1};
shuffle(solutionArray);
System.out.println(Arrays.toString(solutionArray));

输出:

[3, 3, 4, 1, 6, 2, 2, 1, 5, 6, 5, 4]

在Java中,我们可以使用集合。Shuffle方法随机重新排列列表中的项目。

Groovy 3.0.0直接将洗牌和洗牌方法添加到List或数组中。