我需要对以下数组进行随机排序:
int[] solutionArray = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1};
有没有可以做到这一点的函数?
使用集合来洗牌原始类型的数组有些过度了...
你可以很容易地自己实现此函数,例如使用Fisher–Yates shuffle算法:
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;
}
}
}
Collections.shuffle(Arrays.asList(array))
不能生效,因为Arrays.asList(array)
返回的是Collection<int[]>
而不是你所想的Collection<Integer>
。请注意修改。 - Adam StelmaszczykCollections.shuffle
是过度设计? - exhuma这里有一种使用 ArrayList
的简单方法:
List<Integer> solution = new ArrayList<>();
for (int i = 1; i <= 6; i++) {
solution.add(i);
}
Collections.shuffle(solution);
Collectons.shuffle(Arrays.asList(solutionArray));
。该代码会打乱一个包含在solutionArray
中的列表,不会改变列表中元素的数量或值。 - FindOutIslamNow这是一个可工作且高效的Fisher-Yates随机打乱数组函数:
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;
}
}
random.nextInt(int bound)
是排除边界的,但如果将i + 1
作为参数传递给它,则index
和i
有可能相同。 - bmcentee148Xor
技巧在 CPU 没有置换指令且没有可用寄存器时,非常适合交换 CPU 寄存器。但是对于循环内部交换数组元素,我看不到任何好处。对于临时本地变量,没有理由在循环外声明它们。 - Holgertemp
变量会稍微更有效率一些。使用XOR
技巧应该比使用temp
变量更快,但要确保的唯一方法是进行基准测试。 - Dan BrayCollections类有一个高效的洗牌方法,可以被复制,以不依赖于它:
/**
* 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;
}
}
Arrays.asList
。还需要将结果列表转换回数组。 - KitKatArrays.asList()
方法。但是你不需要将其转换回来,因为它只是一个包装器。 - shmosel查看 Collections
类,特别是 shuffle(...)
方法。
java.util
包的一部分。自v1.2以来,它已成为标准库的一部分。 - MauganRaimport java.util.Collections; shuffle(solutionArray);
(翻译您所提供的英文句子) - StevoisiakList<Integer> Shuffle: 43133ns
Integer[] Shuffle: 31884ns
int[] Shuffle: 25377ns
以下是三种不同的洗牌算法实现。如果您处理的是集合,请使用Collections.shuffle。没有必要将数组包装成集合来进行排序。下面的方法非常简单易实现。
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");
}
};
}
}
}
range
、toArray
和toPrimitive
,并循环以便能够得出结论(伪代码:多次执行{生成列表、arr和iarr;计时洗牌列表;计时洗牌arr;计时洗牌iarr})。我的结果是:第1次:list: 36017ns,arr: 28262ns,iarr: 23334ns
。第100次:list: 18445ns,arr: 19995ns,iarr: 18657ns
。这只是表明int[]已经被代码预先优化了,但它们在运行时优化方面几乎是等效的。 - syme这里是使用 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>
),因此它会受到影响。
// Shuffle the elements in the array
Collections.shuffle(Arrays.asList(array));
使用ArrayList<Integer>
可以帮助您解决洗牌问题,而不需要应用太多的逻辑并且消耗更少的时间。以下是我的建议:
ArrayList<Integer> x = new ArrayList<Integer>();
for(int i=1; i<=add.length(); i++)
{
x.add(i);
}
Collections.shuffle(x);
现在您可以使用Java 8:
Collections.addAll(list, arr);
Collections.shuffle(list);
cardsList.toArray(arr);
list
后突然引用cardsList
之间的不一致性之后,它就能正常工作了。但由于你需要创建被省略的临时list
,所以与这里多次展示的Collections.shuffle(Arrays.asList(arr));
方法相比并没有任何优势,该方法自Java2以来也可用。 - Holger
List<int[]>
。请参考我的答案,使用Collections.shuffle()
来实现你想要的结果。 - Duncan Jonesshuffle
方法。 - k314159