今天又发现一个关于完美洗牌的算法。这个比较简单一些,由 microsoft的Peiyush Jain提出。
原论文: A Simple In-Place Algorithm for In-Shuffle. Peiyush Jain, Microsoft Corporation. July 2004 问题描述: 所谓完美洗牌算法即是把输入为: a_1,a_2........a_n,b_1,b_2.........b_n的序列变为 b_1,a_1,b_2,a_2.......b_n,a_n 这是in perfect shufle。相对应的还有out perfect shuffle。两者区别在于首尾元素位置变或不变。 perfect shuffle算法要求在O(n),时间内,O(1)空间内完成。
perfect shuffle实质是一个置换。置换为: i -> 2*i mod (2*n+1) 由于置换可以分解为一系列不相交的轮换之积。故如果能找出所有轮换的一个代表元则可很容易解决问题。 如 n=3时 输入 1 2 3 A B C b => A 1 B 2 C 3所对应的轮换为(1,2,4)(3,6,5) 选代表元为1和3以及一个临时变量T: 2->T,1->2 1 2 3 A B C -----------> _ 1 3 A B C 4->1,T->4 _ 1 3 A B C -----------> A 1 3 2 B C 6->T,3->6 A 1 3 2 B C -----------> A 1 _ 2 B 3 5->3,T->5 A 1 _ 2 B 3 -----------> A 1 B 2 C 3 置换完成 因此问题就转换为求置换的轮换分解中的代表元问题了。 文中巧妙的利用特定条件下每个不相交的轮换可有3的不同幂次生成。
见论文:A Simple In-Place Algorithm for In-Shuffle. 1、问题描述: 所谓完美洗牌算法即是把输入为: a_1,a_2........a_n,b_1,b_2.........b_n的序列变为 b_1,a_1,b_2,a_2.......b_n,a_n perfect shuffle算法要求在O(n),时间内,O(1)空间内完成。 perfect shuffle实质是一个置换。置换为: 由于置换可以分解为一系列不相交的轮换之积。故如果能找出所有轮换的一个代表元则可很容易解决问题。 如 选代表元为1和3以及一个临时变量T: 1 _ A A A 因此问题就转换为求置换的轮换分解中的代表元问题了。 文中巧妙的利用特定条件下: 即(2的任意次幂)对(3的k次幂)取模,能得到一个轮换环,并且环与环之间刚好互不相交 。 考虑某一包含3^s( 1 =< s < k )的轮换。不妨记3^s为a_1,3^k记为m。 则轮换里的数分别为: 则 依此,假设m=9,可以确定每个轮换中,len的值, 如a_1=3^s=3^0=1,则1=2^len * 1 mod m,则 len=2; 如a_1=3^s=3^1=3,则3=2^len * 3 mod m,则 len=6 因此每个3^s开始的一个轮换满足 补充:若对1 2 3 4 5 6 7 8 9 10进行洗牌则首先交换成 1 2 3 4 6 7 8 9 下面举了个例子:洗牌置换过程例证,它例举了将1234ABCD置换成A1B2C3D4的过程,请将图中的n理解为len,k=2。 因此很容易得出各轮换的代表元就为3^0,3^1,3^2......3^i(i<k,i+1>k). 对于2*n不等于3^k-1的情况,可以巧妙的利用这个结论完成ferfect shuffle。 对于2*n不等于3^k-1时,先找一个最接近2*n且比2*n小的2*m=3^k-1。进行如下变换。 把序列中m+1到n+m的子序列循环右移m位。 A_1,A_2,A_3.......A_m-1,A_m,A_m+1......A_n,A_n+1,A_n+2,.......A_n+m,A_n+m+1.....A_2*n -> A_1,A_2,A_3.......A_m-1,A_n+1,A_n+2.....A_n+m,A_m,A_m+1......A_n+m+1................A_2*n 然后对前2*m子序列进行上面的perfect shuffle。然后对剩下的部分进行同样处理。 例如对于长为14的序列进行perfect shuffle置换: 输入序列为: 1 2 3 4 5 6 7 A B C D E F G 14=2*7≠3^k.与14最接近的3^k-1是8=3^2 - 1.因此先对4+1到7+4的子序列循环右移4位得: 1 2 3 4 A B C D 5 6 7 E F G 对前8位进行perfect shuffle移位后得: A 1 B 2 C 3 D 4 5 6 7 E F G 剩下的子序列为 5 6 7 E F G 长度为6 最接近的2*m1=3^k1-1是 m=1 因此对 1+1 到3+1进行循环右移1位得 5 E 6 7 F G 进行2*m的perfect shuffle后得整个序列为: A 1 B 2 C 3 D 4 E 5 6 7 F G 剩下的未处理的子序列为: 6 7 F G 同样的循环移位后为: 6 F 7 G 进行m=1的perfect shuffle得整个序列为: A 1 B 2 C 3 D 4 E 5 F 6 7 G 剩下未处理的子序列为 7 G 长为2的轮换即交换,最后得整个序列为: A 1 B 2 C 3 D 4 E 5 F 6 G 7 完成perfect shuffle。 移位是线性时间,3^k - 1的perfect shuffle置换也是线性时间,最后的递归是对剩下的子序列进行同样的操作,因此整个过程在线性时间内完成。而且需要的辅助空间为常数-个额外临时变量。
实现代码:
|
perfect shuffle 算法的一个线性复杂度实现
最新推荐文章于 2024-04-11 11:48:39 发布