Java 取消混洗复合混洗列表
我正在尝试解混洗一个复合混洗列表。我很难想出如何做到这一点Java 取消混洗复合混洗列表,java,shuffle,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','
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
}
publicstaticvoidmain(字符串[]args){
//随机设置
Random rand=新的Random();
兰特固定种子(5);
//设置列表
ArrayList=newArrayList(Arrays.asList('v','y','2','w','9','n','8','v','a');
//复合洗牌列表
对于(int i=0;i您需要知道的两件事:
。这项声明特别重要:
如果使用同一种子创建了两个Random实例,则
对每个方法调用的顺序相同,它们将生成
返回相同的数字序列
.这一段是关键:
这个实现从上一个向后遍历列表
元素,重复交换随机选择的
元素进入“当前位置”。元素是随机选择的
从列表中从第一个元素到
当前职位(含)
有了这些知识和一两张图表,您应该能够找出如何扭转这种行为。public class Main{
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));
}
}
公共静态void main(字符串[]args){
列表列表=新的ArrayList(Arrays.asList(“A”、“B”、“C”、“D”、“E”、“F”、“G”));
复合洗牌(列表,8,13);
复合填充物(列表,8,13);
系统输出打印项次(列表);
}
publicstaticvoidcompoundshuffle(列表、整数重复、长种子){
随机rand=新随机(种子);
for(int i=0;i
如果在无序化之前知道随机函数的初始种子,那么如果使用相同的种子调用它,则反无序化确实是可能的
事实上,种子
可以被视为此自定义(因此不是一个好的选择)加密算法的加密密钥
假设您正在使用Fisher-Yates洗牌算法(我认为Collections.shuffle显然使用了该算法),请尝试以下洗牌和解洗牌算法。该算法适用于int[],将其更改为您的对象[]
// 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;
}
}
//使用种子实现Fisher–Yates洗牌
公共静态无效随机播放(int[]ar,int seed){
随机r=新随机(种子);
对于(int i=ar.length-1;i>0;i--){
整数指数=r.nextInt(i+1);
//简单交换
int a=ar[指数];
ar[index]=ar[i];
ar[i]=a;
}
}
//实施Fisher–Yates Deshufler
//(您应该知道用于洗牌的**种子**-这是解密密钥)
公共静态无效解shufflarray(int[]ar,int seed){
//重建随机数序列
随机r=新随机(种子);
int[]randoms=新的int[ar.length-1];
int j=0;
对于(int i=ar.length-1;i>0;i--){
randoms[j++]=r.nextInt(i+1);
}
//脱毛
对于(int i=1;i
当你说“unshuffle”时,你的意思是“sort”吗?就像你试图让list
恢复其自然顺序一样?是的,我试图让列表恢复其原始顺序。听起来像是家庭作业实际上是我正在进行的加密的一部分。编写自己的加密通常被认为是一个坏主意(tm)。我没有想到创建一个并行整数数组来比较原始列表。这是天才。@TylerBucher这是唯一明智的做法。尝试执行n
集合。如果不使用此技巧,向后洗牌将非常复杂。顺便说一句,谢谢你的提问。我不知道Collections.shufflee
是可预测的。我认为它会使用内部时钟(或其他东西),所以我学到了一些东西。@pbabcdefp删除shuffle
的第二个参数,或者使用SecureRandom
,但事实并非如此。@ElliottFrisch为此表示感谢。事实上,我以前从未使用过包含两个参数的版本。发现我一直使用的版本还可以,这让我松了一口气。
// 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;
}
}