适合的改组算法

时间:2013-06-13 13:27:26

标签: java algorithm random

只需检查此改组算法是否合适。或者可能有改进?

public static void shuffleArray(Object[] arr, Random rnd){
    int lastIndex = arr.length - 1;
    for (int i=0; i<=lastIndex; i++){
        int k = rnd.nextInt(lastIndex+1);
        Object a = arr[i];
        Object b = arr[k];
        arr[i] = b;
        arr[k] = a;
    }
}

3 个答案:

答案 0 :(得分:4)

您的随机数应在i..lastIndex + 1范围内选择,而不是在0..lastIndex + 1范围内选择。谷歌为费雪耶茨洗牌提供了解释。

您还可以在交换期间通过直接从一个阵列位置复制到另一个阵列而不使用中介来保存一个分配:x = arr [i],arr [i] = arr [k],arr [k] = x。

答案 1 :(得分:4)

如果适合你说的是均匀分布,那么不,它不是。考虑到每次迭代,使用每种可能的配置,您可以以相同的概率生成N个可能的下一个配置。最后,你有N ^ N个相同的可能性,而只有N!个排列,而正常情况下的前者不能被后者分割,因此无法均匀分布。

事实上,我认为杰夫阿特伍德在这里有一个解释:

Coding Horror - The danger of naivete

答案 2 :(得分:1)

  

我需要这个来洗牌一个char(s)

你可以像这样调整shuffle代码用于原语

public static void shuffle(char[] chars, Random rnd) {
    int size = chars.length;
    for (int i = size; i > 1; i--) {
        int idx = rnd.nextInt(i);
        char tmp = chars[idx];
        chars[idx] = chars[i-1];
        chars[i-1] = tmp;
    }
}

你可以做到

Collections.shuffle(Arrays.asList(array), random);

或者您可以查看此代码。使用一个临时变量并随意减小随机大小会稍微高效一些。有关如何执行此操作,请参阅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 {

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

注意:您正在(lastIndex+1)但是lastIndex是arr.length - 1所以这真的只是arr.length