取消复制混合洗牌列表

时间:2015-01-04 21:21:59

标签: java shuffle

我试图取消混合洗牌列表。我无法弄清楚如何实现这一目标。

public static void main(String[] args) {
    // Setup random
    Random rand = new Random();
    rand.setSeed(5);
    // Setup list
    ArrayList<Character> list = new ArrayList<Character>(Arrays.asList('v','y','2','w','9','n','8','v','a'));
    // Compound shuffle list
    for(int i=0;i<5;i++)
        Collections.shuffle(list, rand);
    // un-shuffle list
    // TODO
}

还有我的不洗牌方法。

private static void unshuffle(ArrayList<?> list, Random rand) {
    // Create the sequence backwards
    int[] seq = new int[list.size()];
    for(int i=seq.length; i>1; i--)
        seq[i-1] = rand.nextInt(i);
    // Traverse the sequence and swapping it inversely
    for (int i=0; i<seq.length; i++)
        Collections.swap(list, i, seq[i]);
}

编辑:修复ArrayList。

3 个答案:

答案 0 :(得分:3)

public class Main {

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>(Arrays.asList("A", "B", "C", "D", "E", "F", "G"));
        compoundShuffle(list, 8, 13);
        compoundUnshuffle(list, 8, 13);
        System.out.println(list);
    }

    public static void compoundShuffle(List<?> list, int repetition, long seed) {
        Random rand = new Random(seed);
        for (int i = 0; i < repetition; i++)
            Collections.shuffle(list, rand);
    }

    public static void compoundUnshuffle(List<?> list, int repetition, long seed) {
        helper(list, repetition, seed);
    }

    private static <E> void helper(List<E> list, int repetition, long seed) {
        List<Integer> indices = new ArrayList<Integer>();
        int size = list.size();
        for (int i = 0; i < size; i++)
            indices.add(i);
        compoundShuffle(indices, repetition, seed);
        List<E> copy = new ArrayList<E>(list);
        for (int i = 0; i < size; i++)
            list.set(indices.get(i), copy.get(i));
    }
}

答案 1 :(得分:2)

您需要了解的两件事情:

  1. Behavior of the Random class。该声明特别相关:
  2.   

    如果使用相同的种子创建了两个Random实例,那么   为每个方法调用相同的方法调用,它们将生成和   返回相同的数字序列。

    1. Behavior of the Collections#shuffle() method。这一段是关键:
    2.   

      此实现从最后一个向后遍历列表   元素到第二个,反复交换随机选择   元素进入&#34;当前位置&#34;。元素是随机选择的   从列表中从第一个元素到第一个元素的部分   当前位置,包括在内。

      凭借这些知识和一两个图表,您应该能够弄清楚如何扭转行为。

答案 2 :(得分:0)

如果您在改组之前知道Random函数的初始种子,那么如果使用相同的种子调用它,确实可以进行去混洗。

事实上,seed可以被视为此自定义(所以不是一个好的选择)加密算法的加密密钥。

假设您正在使用Fisher-Yates混洗算法(我认为Collections.shuffle显然使用),请尝试以下算法进行混洗和去混洗。它适用于int [],将其更改为Object []。

// implementing Fisher–Yates shuffling using a seed
public static void shuffleArray(int[] ar, int seed) {
    Random r = new Random(seed);
    for (int i = ar.length - 1; i > 0; i--) {
        int index = r.nextInt(i + 1);
        // simple swap
        int a = ar[index];
        ar[index] = ar[i];
        ar[i] = a;
    }
}   

// implementing Fisher–Yates deShuffler
//(you should know the **seed** used for shuffling - this is the decryption key)
public static void deShuffleArray(int[] ar, int seed) {
    //rebuild your random number sequence
    Random r = new Random(seed);
    int[] randoms = new int[ar.length-1];
    int j = 0;
    for (int i = ar.length - 1; i > 0; i--) {
        randoms[j++] = r.nextInt(i + 1);
    }

    //deShuffling
    for (int i = 1; i < ar.length; i++) {
        //use the random values backwards
        int index = randoms[ar.length - i - 1];
        // simple swap
        int a = ar[index];
        ar[index] = ar[i];
        ar[i] = a;
    }
}