数组元素交叉排列的算法题(a1 a2 a3 .. an b1 b2 b3 .. bn -->a 1 b1, a2 b2, a3 b3, .. an bn ) 概论思想(perfect shuffle 算法)

2023-05-16

perfect shuffle 算法

今天又发现一个关于完美洗牌的算法。这个比较简单一些,由 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  ----------->   ­

                       4->1,T->4 ­

_  1  3   A   B   C  ----------->   ­

                       6->T,3->6 ­

A  1  3   2   B   C  -----------> ­

                       5->3,T->5 ­

A  1  _   2   B   3  -----------> ­

A  1  B   2   C   3   置换完成 ­

因此问题就转换为求置换的轮换分解中的代表元问题了。 ­

文中巧妙的利用特定条件下每个不相交的轮换可有3的不同幂次生成­。

 

我们分析长度2*n=3^k-1的置换的轮换分解。 ­

考虑某一包含3^s( 1 =< s < k )的轮换。不妨记3^s为a_1,3^k记为m。 ­

则轮换里的数分别为: ­

  a_2 =  2* a_1 mod m ­

  a_3 =  2* a_2 mod m; ­

  a_4 =  2* a_3 mod m; ­

    . ­

    . ­

    . ­

  a_n = 2* a_n-1 mod m ­

  a_1 = 2* a_n   mod m ­

­

则    a_1  ≡2^n * a_1 mod m;  ( 最后一项中的a_n用倒数第二行乘2替代,以此类推........) ­

因此每个3^s开始的一个轮换满足 :  3^s ≡3^s * 2^n mod 3^k ­,且长度为n

现假设两个不同的3^s开始的轮换存在相交的元素,记为:p

p≡3^i*2^n mod 3^s

p≡3^j*2^m mod 3^s  (i,j<s)

若n,m都为0,则显然i=j; 假设 i>j

否则应有:3^s |(3^i*2^n -3^j*2^m) ===>3^s |{ 3^i*( 2^n-3^(j-i)*2^m ) }

因为: gcd(3^s , ( 2^n -3^(j-i)*2^m) )=1   注:2^n - 3^(j-i)*2^m 只含2的幂次因子.因为由初等的数论知识可知道

am+bn即m,n的线性组合只能表示gcd(m,n)的倍数.

 

因此上面等式不能成立.

因此每个以不同的3^i开始的轮换不会相交.

上面证明了每个3^i开始的轮换不相交,还需要计算每个3^i起始的轮换覆盖了所有的元素,这可以采用计数的方法证明.

因为每个3^i开始的轮换的长度满足:

                                                  3^i≡3^i *2^N mod3^s 即2^N≡1mod3^(s-i) 

           所以N=φ(3^(s-i))=φ(3^s)/3^i                                 {  gcd (2,3)=1, N是满足等式最小的数}

对i从0到3-1求和就得所有轮换的元素个数为φ(3^s) . 3^s为素数,因此φ(3^s)=3^s-1,即覆盖了所有元素.

 

因此很容易得出各轮换的代表元就为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置换也是线性时间,最后的递归是对剩下的子序列进行同样的操作,因此整个过程在线性时间内完成。而且需要的辅助空间为常数-个额外临时变量。­

 

­实现代码:

#include "stdio.h"

 

 

//轮换
void Cycle(int Data[],int Lenth,int Start)
{
    int Cur_index,Temp1,Temp2;

 

      Cur_index=(Start*2)%(Lenth+1);
      Temp1=Data[Cur_index-1];
      Data[Cur_index-1]=Data[Start-1];
  
  while(Cur_index!=Start)
   {
  Temp2=Data[(Cur_index*2)%(Lenth+1)-1];
        Data[(Cur_index*2)%(Lenth+1)-1]=Temp1;
        Temp1=Temp2;
  Cur_index=(Cur_index*2)%(Lenth+1);
   }
}

 

//数组循环移位 参考编程珠玑
void Reverse(int Data[],int Len)
{
  int i,Temp;
  for(i=0;i<Len/2;i++)
  {
   Temp=Data[i];
   Data[i]=Data[Len-i-1];
   Data[Len-i-1]=Temp;
  }
}
void ShiftN(int Data[],int Len,int N)
{
   Reverse(Data,Len-N);
   Reverse(&Data[Len-N],N);
   Reverse(Data,Len);

}


//满足Lenth=3^k-1的perfect shfulle的实现
void Perfect1(int Data[],int Lenth)
{
     int i=1;

    if(Lenth==2)
  {
   i=Data[Lenth-1];
   Data[Lenth-1]=Data[Lenth-2];
   Data[Lenth-2]=i;
   return;
  }
    while(i<Lenth)
 {
     Cycle(Data,Lenth,i);
     i=i*3;
 }
}
   //查找最接近N的3^k
int LookUp(int N)
{
   int i=3;
   while(i<=N+1) i*=3;

   if(i>3) i=i/3;

   return i;
}

void perfect(int Data[],int Lenth)
{
   int i,startPos=0;
   while(startPos<Lenth)
   {
     i=LookUp(Lenth-startPos);
     ShiftN(&Data[startPos+(i-1)/2],(Lenth-startPos)/2,(i-1)/2);
     Perfect1(&Data[startPos],i-1);
  startPos+=(i-1);
   }
}
#define N 100
 void main()
{
 int data[N]={0};
 int i=0;
 int n;
 printf("please input the number of data you wanna to test(should less than 100):/n");
 scanf("%d",&n);
 if(n&1)
 {
  printf("sorry,the number should be even ");
  return;
 }
 for(i=0;i<n;i++)
  data[i]=i+1;

 perfect(data,n);
 for(i=0;i<n;i++)
   printf("%d   ",data[i]);

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数组元素交叉排列的算法题(a1 a2 a3 .. an b1 b2 b3 .. bn -->a 1 b1, a2 b2, a3 b3, .. an bn ) 概论思想(perfect shuffle 算法) 的相关文章

  • 数组元素交叉排列的算法题(a1 a2 a3 .. an b1 b2 b3 .. bn -->a 1 b1, a2 b2, a3 b3, .. an bn ) 概论思想(perfect shuffle 算法)

    perfect shuffle 算法 今天又发现一个关于完美洗牌的算法 这个比较简单一些 xff0c 由 microsoft的Peiyush Jain提出 原论文 xff1a A Simple In Place Algorithm for
  • spark中shuffle运行原理

    ShuffleManager里有四个接口 register reader writer和stop 核心接口则是reader和writer 当前版本reader接口只有1个实现 writer接口有3个实现 每种实现分别对应不同的场景 writ
  • 使用 JavaScript Array.sort() 方法进行洗牌是否正确?

    我正在帮助某人解决他的 JavaScript 代码 我的目光被如下所示的部分吸引了 function randOrd return Math round Math random 0 5 coords sort randOrd alert c
  • 在java中洗牌JSON数组的有效方法?

    哪种方法最好 现在 我将我的JSONArray to an ArrayList自定义类的 使用Collections shuffle 执行该操作 并转换回JSONArray 这似乎开销太大 答案可能只是实施一个费舍尔 耶茨洗牌对于它 但我的
  • C++。加权 std::shuffle

    有没有一种方法可以使用标准库进行漂亮而优雅的加权洗牌 有std discrete distribution 我想要的是这样的 std vector
  • 使用 IComparer 进行随机播放

    首先 我确实了解费舍尔 耶茨洗牌法 但为了论证起见 我想允许用户从下拉列表中选择排序选项 该列表将包括 随机 选项 根据他们的选择结果 我只想用 IComparer 实例替换我的排序 IComparer 会是什么样子 谷歌带来了大量有缺陷的
  • 种子洗牌可以逆转吗?

    采用这个函数 它是一个有种子的 Fisher Yates 洗牌 顺序是随机的 但在给定相同种子的情况下可以重现 function seeded shuffle array items seed false items array value
  • JavaScript 中的 str_shuffle() 等效项?

    像str shuffle PHP中的函数 是否有类似的函数在javascript中打乱字符串 请帮忙 不存在这样的函数 你自己写一个 这是一个例子 function shuffle string var parts string split
  • 为什么 random.shuffle 返回 None ?

    Why is random shuffle返回None在Python中 gt gt gt x foo bar black sheep gt gt gt from random import shuffle gt gt gt print sh
  • 【Shuffle Attention】《SA-Net:Shuffle Attention for Deep Convolutional Neural Networks》

    ICASSP 2021 文章目录 1 Background and Motivation 2 Related Work 3 Advantages Contributions 4 Method 5 Experiments 5 1 Datase
  • 在分区内的多个列上进行 Spark 聚合,无需进行洗牌

    我正在尝试在多个列上聚合数据框 我知道聚合所需的所有内容都在分区内 也就是说 不需要洗牌 因为聚合的所有数据都是分区本地的 采取example http dmtolpeko com 2015 02 12 multi column key a
  • 有没有办法将 Knuth shuffle 应用于 Stack 数据结构?

    对于编程课 我正在为第一个家庭作业创建一个二十一点程序 教授给了我们一个示例 Card 类 其中包括将它们添加到牌组中的方法 对于她的牌组 她使用 ArrayList 您可以使用 Collections shuffle 方法轻松地进行 Kn
  • 高效地从 PHP 数组中选取 n 个随机元素(无需随机播放)

    我有以下代码可供选择 n数组中的元素 array in PHP shuffle array result array splice array 0 n 给定一个大数组但只有几个元素 例如5 out of 10000 这相对较慢 所以我想对其
  • 数组的随机打乱

    我需要随机洗牌以下数组 int solutionArray 1 2 3 4 5 6 6 5 4 3 2 1 有什么功能可以做到这一点吗 使用集合来打乱原始类型数组有点过分了 自己实现该功能非常简单 例如使用费舍尔 耶茨洗牌 http en
  • 在 Objective-C 中打乱 NSString 中的字母

    我写了这个函数 它会打乱 a 的内容NSString 它似乎可以工作 但时不时会崩溃 这可能是一种迂回的方式 但我将字符放入一个数组中 随机交换数组中的元素 然后将数组转回字符串 我不确定我正在做的事情是不安全的 这会导致它崩溃 我想这可能
  • Xcode 构建完美失败——找不到 COpenSSL

    代码 8 0 Swift 工具链 3 0 版本 完美的 Package url https github com PerfectlySoft Perfect HTTPServer git majorVersion 2 minor 0 跑起来
  • 不重复的随机数

    我需要生成大约 9 1 亿个不重复的随机数 范围从零到生成的数字数量 并且我需要它们非常快速地生成 对类似问题的几个答案提出了简单地对数组进行洗牌以获得随机数 而其他答案则提出使用布隆过滤器 问题是 哪一个更有效 如果是布隆过滤器 我该如何
  • 使用 Tensorflow 对象检测 api 打乱训练数据集

    我正在使用 Faster RCNN 模型和 Tensorflow 对象检测 API 来开发徽标检测算法 我的数据集按字母顺序排列 因此有一百个阿迪达斯徽标 然后是一百个苹果徽标等 我希望在训练时对其进行洗牌 我在配置文件中添加了一些值 tr
  • 朴素洗牌的现实问题

    我正在写一些文章 旨在通过使用与扑克相关的主题来教授入门编程概念 目前 我正在研究洗牌的主题 As 杰夫 阿特伍德 Jeff Atwood 在 CodingHorror com 上指出 http www codinghorror com b
  • 为什么 Fisher Yates 是最有用的洗牌算法?

    您认为现代版本的 Fisher Yates 是最公正的洗牌算法吗 您如何解释数组中每个元素位于其原始位置的概率为 1 n 给定一个完美的伪随机数生成器 梅森扭转者 http en wikipedia org wiki Mersenne Tw

随机推荐

  • MIC电路原理

    一 MIC 的电路原理 FET xff1a 场效应管 MIC 的主要器件 xff0c 起到阻抗变换和放大的作用 C xff1a 是一个可以通过膜片震动而改变电容量的电容 xff0c 声电转换的主要部件 C1 C2 xff1a 是为了防止射频
  • SecureCRT crt.Screen.WaitForString用法

    在SecureCRT里 xff0c 用得最多的应该就是crt Screen xff0c 基本上很多操作都是基于屏幕的返回字来决定下一步的操作 这里脚本语言使用VBScript 进行讲解 61 61 61 61 61 61 61 61 61
  • debian9.13系统安装libreoffice6.4.6

    1 在root用户下 apt get remove purge libreoffice 2 切换到下载好的软件包位置 xff0c 然后执行 3 解压Libreoffice安装包和汉化包 tar zxvf LibreOffice 6 4 6
  • tftp和xinetd服务器的配置

    为了开机启动tftpd服务器 需要用到配置xinetd服务器 所以顺便研究下 与xinetd服务器相关的配置就1个文件和1个目录 etc xinetd conf etc xinetd d vim etc xinetd conf defaul
  • c语言 inline函数的总结

    1 inline只是个编译器建议 xff0c 编译器不一定非得展开Inline函数 例如 xff1a Inline函数地址引用 inline在递归函数中使用 2 inline必须用于函数定义 xff0c 对于函数声明 xff0c inlin
  • Linux线程挂掉是否影响进程

    严格的说没有 线程崩溃 xff0c 只是触发了SIGSEGV Segmentation Violation Fault 如果没有设置对应的Signal Handler操作系统就自动终止进程 xff08 或者说默认的Signal Handle
  • python matplotlib.subplot绘制子图

    版权声明 xff1a 本文为博主原创文章 amp amp 转载请著名出处 64 http blog csdn net gatieme 目录 43 问题描述subplot函数介绍示例程序 1 规则划分成33的2 不规则划分 CSDNGitHu
  • SIFT 三线性差值原理与代码分析

    参考了文章 http blog csdn net fzthao article details 62424271 Jie Pro 在进行特征描述时 xff0c 讲的非常详细 但未对三线性插值进行阐述 我也是花了好久的时间才慢慢搞懂 有错之处
  • Cortex-M3的PendSV中断以及uCOS系统一点思考

    uCOS中 OSStart函数 OSStartHighRdy函数 会重新设置PendSV中断的优先级 把该中断优先级设置为最低 每次时钟中断时 一般为最高优先级 xff0c 查看是否要进程切换 如果此时有中断嵌套则不进行进程切换 xff0c
  • opencv3.2安装opencv_contrib

    opencv3 2 增加opencv contrib组件 之前在ubuntu16 04下安装caffe和opencv3 2 xff0c 由于需要需要使用opencv contrib组件 xff0c 在安装中遇到一些问题 在已安装好openc
  • 最小二乘法

    最小二乘法 xff08 又称最小平方法 xff09 是一种数学优化技术 它通过最小化误差的平方和寻找数据的最佳函数匹配 利用最小二乘法可以简便地求得未知的数据 xff0c 并使得这些求得的数据与实际数据之间误差的平方和为最小 最小二乘法还可
  • python vstack

    Python numpy函数hstack vstack stack dstack vsplit concatenate 感觉numpy hstack 和numpy column stack 函数略有相似 xff0c numpy vstack
  • Linux下VNC Server的配置

    1 xff09 安装vnc server xff1a rpm ivh tigervnc server 1 1 0 5 el6 x86 64 rpm 2 修改配置文件 xff0c 1 表示第1号桌面 xff0c 对应端口号5901 2 表示2
  • WIN10_GTX1650_深度学习环境搭建

    这篇博客总结的非常好 xff0c 但安装过程中可能会碰到一些问题 在这记录 xff0c 分享一下解决方案 https blog csdn net weixin 45755980 article details 105397874 Tenso
  • Linux面试必备20个常用命令

    文章目录 第一章 什么是linux第二章 linux的基础命令1 pwd 命令2 ls 命令3 cd 命令4 man 命令5 grep 命令6 find 命令7 chmod 命令8 ps 命令9 kill 命令10 tail 命令11 ne
  • Python爬虫实战(一):翻页爬取数据存入SqlServer

    目录 前言爬取目标准备工作代码分析1 设置翻页2 获取代理ip3 发送请求4 获取详情页地址5 提取详情信息6 存入数据库7 循环实现翻页8 启动 前言 x1f525 x1f525 本文已收录于Python爬虫实战100例专栏 xff1a
  • 已解决error: subprocess-exited-with-error

    已解决 xff08 pip安装第三方模块lxml模块报错 xff09 Building wheels for collected packages lxml Building wheel for lxml setup py error er
  • 已解决此处缺少‘,‘, ‘]‘字符, 实际上是一个 ‘EOF‘

    已解决Python解析JSON xff0c 抛出此处缺少 39 39 39 字符 实际上是一个 39 EOF 异常的解决方法 xff0c 亲测有效 文章目录 报错问题报错原因解决方法千人全栈VIP答疑群联系博主帮忙解决报错 报错问题 粉丝群
  • 已解决E: Unable to locate package ros-kinetic-desktop-full

    已解决Ubuntu安装ros xff0c 抛出异常E Unable to locate package ros kinetic desktop full的正确解决方法 xff0c 亲测有效 xff0c 文末附上Ubuntu系统对应ros系统
  • 数组元素交叉排列的算法题(a1 a2 a3 .. an b1 b2 b3 .. bn -->a 1 b1, a2 b2, a3 b3, .. an bn ) 概论思想(perfect shuffle 算法)

    perfect shuffle 算法 今天又发现一个关于完美洗牌的算法 这个比较简单一些 xff0c 由 microsoft的Peiyush Jain提出 原论文 xff1a A Simple In Place Algorithm for