Look at 费舍尔-耶茨洗牌 http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle一种基于键排列字符串的方法。将密钥作为种子输入 PRNG,用它来生成 shuffle 使用的随机数。
现在,如何逆转该过程? Fisher-Yates 的工作原理是交换某些元素对。因此,要反转该过程,您可以将相同的密钥输入相同的 PRNG,然后运行 Fisher-Yates 算法as if您正在对字符串大小的数组进行洗牌。但实际上你没有移动任何东西,只是记录每个阶段将被交换的元素的索引。
完成此操作后,请浏览您的交换列表相反,将它们应用到打乱的字符串上。结果是原始字符串。
例如,假设我们使用以下交换对字符串“hello”进行了洗牌(我在这里没有使用 PRNG,我掷骰子,但 PRNG 的要点是,它给你相同的数字序列,给定相同的数字序列)。种子):
(4,0): "hello" -> "oellh"
(3,3): "oellh" -> "oellh"
(2,1): "oellh" -> "olelh"
(1,0): "olelh" -> "loelh"
所以,打乱后的字符串是“loelh”。
为了进行洗牌,我生成相同系列的“随机”数字 0、3、1、0。然后以相反的顺序应用交换:
(1,0): "loelh" -> "olelh"
(2,1): "olelh" -> "oellh"
(3,3): "oellh" -> "oellh"
(4,0): "oellh" -> "hello"
Success!
当然,这样做的缺点是它会使用大量内存进行洗牌:索引数组与原始字符数组一样长。因此,对于真正巨大的数组,您可能需要选择一个 PRNG(或者无论如何一个序列生成函数),它可以向前或向后步进,而无需存储所有输出。这排除了基于散列的加密安全 PRNG,但 LFSR 是可逆的。
顺便说一句,你为什么要这样做?