随机改组阵列

Hub*_*ert 214 java arrays shuffle

我需要随机调整以下数组:

int[] solutionArray = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1};
Run Code Online (Sandbox Code Playgroud)

这有什么功能吗?

Phi*_*Lho 250

使用Collections来混合一组原始类型有点过分了......

使用例如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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 使用Collections.shuffle(Arrays.asList(array))会好得多; 然后打乱你的自我. (50认同)
  • 非常琐碎的挑剔,但你可以使用`println()`而不是'println("")`.意思更清楚我认为:) (25认同)
  • @Louie`Collections.shuffle(Arrays.asList(array))`不起作用,因为`Arrays.asList(array)`按你的想法返回`Collection <int []>`而不是`Collection <Integer>`. (20认同)
  • @exhuma因为如果你有一个数千或数百万个原始值的数组要进行排序,那么在一个对象中包装它们只是为了进行排序在内存和CPU中都有点贵. (14认同)
  • 这不是**Fisher-Yates shuffle.这被称为[Durstenfeld shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm).最初的渔民洗牌在O(n ^ 2)时间内运行,这是非常缓慢的. (10认同)
  • 为什么“Collections.shuffle”太过分了? (3认同)
  • @ ShoeLace1291如果我没有记错,你就不能用Java:没有办法让一个方法与基元(int)和对象(字符串)一起工作.你必须复制它. (2认同)

met*_*din 152

这是一个使用的简单方法ArrayList:

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

  • 你可以简单地`Collections.shuffle(Arrays.asList(solutionArray));` (4认同)
  • 这个答案是怎么回事。它甚至没有试图回答标题中的问题。视线中甚至没有任何阵列。 (3认同)

Dan*_*ray 96

这是一个有效且高效的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];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要么

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @ bmcentee148允许以随机顺序交换元素.不理解这削弱了Enigma并帮助Alan Turing破解它.https://en.wikipedia.org/wiki/Cryptanalysis_of_the_Enigma#The_Enigma_machines (21认同)
  • 当CPU没有交换指令并且没有空闲寄存器时,`xor`技巧非常适合交换CPU寄存器,但是为了在循环内交换数组元素,我看不到任何好处.对于临时局部变量,没有理由在循环外声明它们. (4认同)
  • 第二个实现是否有可能与自己的索引交换?`random.nextInt(int bound)`是独占的,但给它`i + 1`作为参数将允许`index`和`i`可能是相同的. (2认同)

Kit*_*Kat 22

Collections类有一个有效的shuffling方法,可以复制,以免依赖它:

/**
 * 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您不能在原始数组上使用 Arrays.asList() 。而且您不需要将其转换回来,因为它只是一个包装器。 (3认同)

Dav*_*ave 12

Collections具体来说,看看课程shuffle(...).

  • 你如何在Android中使用这个Collections类?你需要做一个特殊的导入(CRTL SHIT O不起作用)来使用它吗? (8认同)
  • @gla3dr It should be below the "ANY" key. (5认同)
  • 为了使您的答案更加自包含,它应该包含示例代码.IE:`import java.util.Collections; 洗牌(solutionArray);` (2认同)

Dun*_*nes 9

以下是使用该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);
  }    
}
Run Code Online (Sandbox Code Playgroud)

请注意,它与Java的无能遭受因之间的顺利转换int[]Integer[](因此int[]List<Integer>).


Mr.*_*irl 9

你有两个选择.在洗牌时,列表与数组略有不同.

如下所示,数组比列表快,并且基本数组比对象数组快.

样本持续时间

List<Integer> Shuffle: 43133ns
    Integer[] Shuffle: 31884ns
        int[] Shuffle: 25377ns
Run Code Online (Sandbox Code Playgroud)

下面是一个shuffle的三种不同实现.如果您正在处理集合,则应该只使用Collections.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;
Run Code Online (Sandbox Code Playgroud)

主要方法

    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);
    }
Run Code Online (Sandbox Code Playgroud)

洗牌一般列表

    // ================================================================
    // 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;
    }
Run Code Online (Sandbox Code Playgroud)

改组通用阵列

    // ================================================================
    // 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;
    }
Run Code Online (Sandbox Code Playgroud)

改组原始数组

    // ================================================================
    // 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;
    }
Run Code Online (Sandbox Code Playgroud)

实用方法

将数组复制并转换为列表的简单实用方法,反之亦然.

    // ================================================================
    // 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;
    }
Run Code Online (Sandbox Code Playgroud)

范围类

生成一系列值,类似于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");
                }
            };
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您没有为相同的事情计时,并且您只为每个事情计时一次(然后它们的顺序计数并且您忘记了运行时优化)。您应该在任何计时之前调用“range”,“toArray”和“toPrimitive”,并循环以能够得出任何结论(伪代码:执行几次{生成列表,arr和iarr;时间洗牌列表;时间洗牌arr;时间打乱iarr})。我的结果:第一:“列表:36017ns,arr:28262ns,iarr:23334ns”。第 100 个:`列表:18445ns,arr:19995ns,iarr:18657ns`。它只是显示 int[] 已预先优化(通过代码),但它们几乎与运行时优化相同。 (2认同)

小智 8

使用ArrayList<Integer>可以帮助您解决混乱问题,而无需应用太多逻辑并消耗更少的时间.这是我的建议:

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


小智 7

以下代码将在数组上实现随机排序.

// Shuffle the elements in the array
Collections.shuffle(Arrays.asList(array));
Run Code Online (Sandbox Code Playgroud)

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

  • 请注意,它不适用于原始数组,因为 Arrays.asList 将原始数组视为一个元素 (2认同)

Ива*_*чук 5

您现在可以使用 java 8:

Collections.addAll(list, arr);
Collections.shuffle(list);
cardsList.toArray(arr);
Run Code Online (Sandbox Code Playgroud)

  • 这段代码中没有任何特定于 Java8 的内容。这从 Java2 开始有效。好吧,一旦你解决了第一次使用 `list` 和突然引用 `cardsList` 之间的不一致,它就会起作用。但是,由于您需要创建已省略的临时 `list`,因此这里多次显示的 `Collections.shuffle(Arrays.asList(arr));` 方法没有任何好处。这也适用于 Java2。 (2认同)