【问题标题】:Un-shuffle a compound shuffled list取消混洗复合混洗列表
【发布时间】:2015-01-04 21:21:59
【问题描述】:

我正在尝试取消混洗复合混洗列表。我无法弄清楚如何做到这一点。

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
}

还有我的 un-shuffle 方法。

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。

【问题讨论】:

  • 当你说“unshuffle”时,你的意思是“sort”吗?就像您试图让list 恢复其自然秩序一样?
  • 是的,我正在尝试将列表恢复到原来的顺序。
  • 听起来像功课
  • 它实际上是我正在做的加密的一部分。
  • 编写自己的加密通常被认为是一个坏主意(tm)。 security.stackexchange.com/questions/18197/…

标签: java shuffle


【解决方案1】:
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));
    }
}

【讨论】:

  • 我没有想到创建一个并行整数数组来比较原始列表。这是天才。
  • @TylerBucher 这是唯一明智的做法。如果没有这个技巧,试图向后做nCollections.shuffle 会非常复杂。顺便说一句,谢谢你的问题。我不知道Collections.shuffle 是可以预测的。我以为它会使用内部时钟(或其他东西),所以我学到了一些东西。
  • @pbabcdefp 删除shuffle 的第二个参数或使用SecureRandom,它不是。
  • @ElliottFrisch 谢谢。实际上,我以前从未使用过带有 2 个参数的版本。发现我一直在使用的版本没问题,我松了一口气。
【解决方案2】:

你需要知道的两件事:

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

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

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

此实现从最后一个向后遍历列表 直到第二个元素,反复交换随机选择的元素 元素进入“当前位置”。元素是随机选择的 从列表中从第一个元素到 当前位置,含。

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

【讨论】:

    【解决方案3】:

    如果您在洗牌之前知道 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-09-03
      • 1970-01-01
      • 1970-01-01
      • 2021-12-05
      • 2023-04-10
      • 1970-01-01
      • 2019-01-31
      • 2021-02-11
      • 2021-10-05
      相关资源
      最近更新 更多