随机洗牌数组
我需要随机洗牌下面的数组:
int[] solutionArray = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1};
有什么function吗?
使用集合来洗牌一个原始types的数组是有点矫枉过正…
使用例如Fisher-Yates shuffle来实现这个function是很简单的:
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洗牌arraysfunction:
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; } }
看Collections
类,特别是shuffle(...)
。
这是一个使用Collections.shuffle
方法的完整解决scheme:
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>
)之间平滑转换,所以会受到影响。
使用ArrayList<Integer>
可以帮助您解决洗牌问题,而无需使用大量的逻辑和更less的时间。 这是我的build议:
ArrayList<Integer> x = new ArrayList<Integer>(); for(int i=1; i<=add.length(); i++) { x.add(i); } Collections.shuffle(x);
你在这里有几个选项。 当涉及到洗牌时,列表与数组有点不同。
正如你在下面看到的,一个数组比一个列表快,并且一个基本数组比对象数组快。
样本持续时间
List<Integer> Shuffle: 43133ns Integer[] Shuffle: 31884ns int[] Shuffle: 25377ns
下面是洗牌的三种不同的实现。 如果你正在处理一个集合,你应该只使用Collections.shuffle。 没有必要把你的数组封装到一个集合中,以便对它进行sorting。 下面的方法实现起来非常简单。
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"); } }; } } }
以下代码将在数组上实现随机sorting。
// 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/
这是一个数组的generics版本:
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()是可取的。 然而,性能testing并没有显示出以上与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
,则会清理所有元素。
你现在可以使用java 8:
Collections.addAll(list, arr); Collections.shuffle(list); cardsList.toArray(arr);
我正在考虑这个非常受欢迎的问题,因为没有人写过洗牌拷贝的版本。 风格是从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; }
这是knuth shufflealgorithm。
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]); } }
还有另一种方式,还没有发布
//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); }
这种方式更容易,取决于上下文
数组中随机混排的最简单的解决scheme。
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]); }
这是一个使用Apache Commons Math 3.x(仅用于int []数组)的解决scheme:
MathArrays.shuffle(array);
或者,Apache Commons Lang 3.6向ArrayUtils
类(针对对象和任何原始types)引入了新的shuffle方法。
ArrayUtils.shuffle(array);
我在一些答案中看到了一些遗漏信息,所以我决定添加一个新的答案。
Java集合Arrays.asList采用typesT (T ...)
var-arg。 如果传递一个基本数组(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); } } }