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

2023-11-01

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 算法) 的相关文章

  • DPLL算法定义

    我在理解 DPLL 算法时遇到一些问题 我想知道是否有人可以向我解释它 因为我认为我的理解是不正确的 我理解的方式是 我采用一些文字集 如果每个子句都为真 则模型为真 但如果某些子句为假 则模型为假 我通过查找单元子句递归地检查模型 如果有
  • 如何验证无锁算法?

    从理论上讲 至少应该可以对无锁算法进行暴力验证 只有这么多的函数调用组合 是否有任何工具或正式推理过程可以实际证明无锁算法是正确的 理想情况下它还应该能够检查竞争条件和 ABA 问题 注意 如果你知道一种方法来证明一点 例如 只证明它不受
  • 算法 - 如何有效删除列表中的重复元素?

    有一个list L 它包含以下元素任意类型each 如何有效删除此类列表中的所有重复元素 必须保留订单 只需要一个算法 因此不允许导入任何外部库 相关问题 在Python中 从列表中删除重复项以使所有元素都是唯一的最快算法是什么在维持秩序的
  • Python:for 循环 - for i in range(0,len(list) 与 for i in list

    这是一个非常简单的Python 力学问题 为什么我不能只说 for i in range original list 而不是 for i in range 0 len original list 人们通常使用范围而不是前者吗 谢谢 If I
  • 地图应用的聚类算法

    我正在研究地图上的聚类点 纬度 经度 对于快速且可扩展的合适算法有什么建议吗 更具体地说 我有一系列纬度 经度坐标和一个地图视口 我正在尝试将靠近的点聚集在一起以消除混乱 我已经有了解决问题的方法 see here http bouldr
  • 为什么我的 Project Euler Problem 12 算法这么慢?

    我已经在 Scala 中为 PE P12 创建了解决方案 但速度非常非常慢 有人可以告诉我为什么吗 如何优化这个 calculateDevisors 简单的方法和calculateNumberOfDivisors 除数函数具有相同的速度 i
  • 计算具有 3 个循环的算法的复杂度

    我尝试解决以下练习 以下代码片段最坏情况运行时间的增长顺序是什么 作为 N 的函数 int sum 0 for int i 1 i lt N i for int j 1 j lt i i j for int k 1 k lt j j k s
  • 如何设计一种算法来计算倒数式数学数字难题

    我一直想这样做 但每次我开始思考这个问题时 它的指数性质都会让我大吃一惊 我希望能够理解的问题解决器和代码是针对倒计时数学问题的 给定一组数字 X1 到 X5 计算如何使用数学运算将它们组合起来生成 Y 您可以应用乘法 除法 加法和减法 那
  • 如何在单向链表(一次遍历中)中从尾部获取第 n 个节点?

    所以我在一次考试中得到了这个问题 如何从单链表的尾部获取第 n 个节点 每个节点都有一个值和一个下一个 指向下一个值的指针 我们得到这个 getNodeFromTail Node head int x 所以我的做法是通过遍历一次来求出列表的
  • 当平方和为N时,如何找到四个变量的所有可能值?

    A 2 B 2 C 2 D 2 N给定一个整数N 打印出整数值的所有可能组合ABCD求解方程 我猜我们可以比暴力做得更好 天真的暴力会是这样的 n 3200724 lim sqrt n 1 for a 0 a lt lim a for b
  • 神经网络的层和神经元

    我想更多地了解神经网络 我正在开发一个 C 程序来制作神经网络 但我坚持使用反向传播算法 很抱歉没有提供一些工作代码 我知道有很多库可以用多种语言创建神经网络 但我更喜欢自己制作一个 关键是我不知道要实现特定目标 例如模式识别或函数近似或其
  • 计算字符串的所有子串中子序列的出现次数

    我想编写一个算法来计算字符串的所有子字符串中字符子序列 不相交 出现的总数 下面是一个例子 字符串 jabcohnnyjohnny 后续 约翰尼 包含子序列的子字符串 jabcohnny jabcohnnyj jabcohnnyjo jab
  • 素数生成器算法

    我一直在尝试解决素数生成算法的SPOJ问题 这是问题 彼得想为他的密码系统生成一些素数 帮助 他 你的任务是生成两个给定之间的所有素数 数字 Input 输入以单行中测试用例的数量 t 开始 t Output 对于每个测试用例 打印所有素数
  • 从原点开始在离散 2D 网格上迭代向外螺旋的算法

    例如 这是预期螺旋的形状 以及迭代的每个步骤 y 16 15 14 13 12 17 4 3 2 11 18 5 0 1 10 x 19 6 7 8 9 20 21 22 23 24 其中线条是 x 轴和 y 轴 以下是算法每次迭代 返回
  • 定点数学比浮点运算快吗?

    多年前 即 20 世纪 90 年代初期 我构建了图形软件包 该软件包基于定点算术和预先计算的 cos sin 表格以及使用牛顿近似方法进行 sqrt 和对数近似的缩放方程来优化计算 这些先进技术似乎已经成为图形和内置数学处理器的一部分 大约
  • Python Pandas:沿一列比较两个数据帧,并返回另一个数据帧中两个数据帧的行内容

    我正在处理两个 csv 文件并作为数据框 df1 和 df2 导入 df1 有 50000 行 df2 有 150000 行 我想将 df2 的 时间 与 df1 求时间差并返回所有列的值 对应相似的行 保存在df3中 时间同步 例如 35
  • 如何为多边形创建内部螺旋?

    对于任何形状 我如何在其内部创建类似形状的螺旋 这与边界 使用 Minkowski 和 类似 尽管它会是相同形状的螺旋 而不是在形状内部创建相同的形状 我找到了这个 http www cis upenn edu cis110 13su le
  • less.js - 在解析器回调中获取变量值

    我正在使用 less js 1 3 0 在客户端将 less 解析为 css 在解析器的回调中 我想获取每个变量的值 我尝试了以下方法但没有成功 var data colour red example background color co
  • heapq.nlargest 的时间复杂度是多少?

    我在看演讲者说 获得t列表中最大的元素n元素可以在O t n 这怎么可能 我的理解是创建堆将是O n 但是复杂度是多少nlargest本身就是O n t or O t 实际的算法是什么 在这种情况下 说话者是错误的 实际成本是O n log
  • Webpack 4:如何使用 LESS 获取 CSS 源映射?

    多年来我一直在尝试让 CSS 源映射在 webpack 中工作 但没有成功 我不确定链条中哪里出了问题 我希望有人能指出我正确的方向 这是发生的事情 行号是错误的 实际上文件名也是错误的 main less只是包含一堆 import也就是说

随机推荐

  • JVM类加载过程和编译器优化

    文章目录 1 加载 2 链接 2 1 验证 2 2 准备 2 3 解析 3 初始化 3 1 类初始化练习 3 2 懒汉式单例练习 4 类加载器 4 1 启动类加载器 4 2 扩展类加载器 4 3 双亲委派模式 4 4 线程上下文类加载器 4
  • PCL——VTK读取、保存.ply模型数据

    目录 一 读取 ply文件 1 代码示例 2 结果展示 一 保存 ply文件 1 代码示例 2 结果展示 一 读取 ply文件 ReadPLY 是VTK内置的mesh模型读取函数 该函数仅支持 ply格式的mesh网格数据不支持读取 ply
  • 【STM32】HAL库——ADC

    前期准备 STM32CubeMX STM32RCT6核心板 IDE Keil MDK ARM STM32CubeMX部分 1 配置时钟 选择STM32F103RCTx系列芯片 配置时钟的同时会自动配置IO口引脚 将HCLK设置为最大频率72
  • Altera FPGA PCIE 例程仿真

    由于刚开始学PCIE接口 所以按照官方给的例程进行仿真操作 下面主要介绍下仿真的具体步骤 该例子是采用Cyclone V器件进行仿真 PCIE为gen1X4 的 Quartus II 版本号为15 0 Modelsim为ModelsimSE
  • 小米商城网页制作大全-完结篇

    时隔多日 小米商城网页基本完成 跳转的第二页面没有做 在这过程中遇到了很多小而细的问题 例如浏览器兼容性 字符图标不显示 动画效果不起作用等 抽时间整理一下 再继续完善 效果图如下 实际右侧固定栏只有个人中心 购物车 联系客服 回到顶部四项
  • 【websocket定义和使用】

    文章目录 前言 一 websocket定义 2 websocket使用 总结 前言 websocket就是服务端和客户端建立长连接的一种方式 多在直播 弹幕 聊天业务中使用 具体的自己百度吧 一 websocket定义 代码如下 示例 fu
  • docker 服务编排

    一 docker 服务编排 微服务的应用系统中一般包含若干个微服务 每个微服务一般都会部署多个实例 如果每个微服务都要手动启停 维护的工作量会很大 要从dockerfile build image 或者去 dockerhub 拉取image
  • Flutter 指针事件原理&点击穿透

    隔离的这14天 慢慢的研究了Flutter的指针事件 在这个过程中 又重新梳理了一下Element和Render Tree的形成过程 这篇文章 主要对指针事件在Fluter中如何下发到各个组件的过程进行梳理 指针是指针 手势是手势 手势是指
  • 软件工程课件

    软件工程 考点概述 软件工程概述 能力成度模型 能力成熟度模型集成 软件过程模型 逆向工程 软件需求 需求获取 数据流图 需求定义 考点概述 重点章节 软件工程概述 之前老版教程的 之前考过 能力成度模型 记忆 能力等级 和 特点 能力成熟
  • (读书笔记)python数据处理-(python读取csv、excel文件)

    文章目录 python读取csv文件 python解析excel文件 1 查看工作表中的sheet名 2 查看工作表指定sheet的内容 3 查看sheet中每个元素 4 将提取信息以字典形式展示 python 判断excel文件是否存在
  • Java使用RabbitMQ

    一 简介 rabbitMQ是什么 怎么用 怎么安装 网上文档一大把 请自行百度 本文给出的代码是rabbitMQ的fanout交换机模式 最原生的java代码 如果需要使用其他模式的rabbitMQ 请自行更改相应部分代码 二 代码 rab
  • 浅学Oracles数据库

    一 Oracle数据库中的数据类型 1 1 关于mysql数据库中的数据类型 int 整数型 bigint 长整型 float 单精度浮点型 double 双精度浮点型 char 字符型 长度不可变 varchar 字符型 长度可变 dat
  • C 函数参数传递一级指针和二级指针的区别

    文章目录 一 概念 二 函数参数为一级指针例子 1 程序一 指针类型为基本数据 2 程序二 参数为结构体 不是指针类型 3 程序三 参数类型为结构体指针 三 函数参数为二级指针例子 1 程序四 二级指针类型为基本数据类型 2 程序五 二级指
  • Element UI DatePicker 监听年月切换按钮并获取变更

    需求 在每切换一次年月时调用接口获取数据 传参为当前切换成的年月 需要监听DatePicker是否显示 用input获得焦点时触发的focus事件 element自带 并绑定4个切换按钮的click事件 html
  • Vue3 优雅地监听 localStorage 变化

    最近在研究框架 也仔细用了Vue3一些功能 今天分享一次我的实践 Vue3如何监听localStorage的变化 为什么要这样做 原生的localStorage只能监听同源地址下不同页面的localStorage变化 作为单页面应用 显然不
  • Tip of the Week #10: Splitting Strings, not Hairs

    Tip of the Week 10 Splitting Strings not Hairs Originally published as totw 10 on 2012 08 16 By Greg Miller jgm google c
  • 前端面试题及答案(字节跳动)(一)

    目录 垂直居中 左侧固定 右侧自适应 如何判断一个值是数组 bigint 最大安全整数 如何判断某个字符串以 abc 开头 进程和线程的区别 tcp 与 udp 跨域问题的几种解决方案 option 预请求 跨域的同时携带 cookie 用
  • LeetCode 处理用时最长的那个任务的员工

    解题思路 把第一个一维数组的两个元素分别定义为最大值和id 之后遍历进行判断 class Solution public int hardestWorker int n int logs int max logs 0 1 int id lo
  • sql注入知识---堆叠注入

    MySQL手注之堆叠注入详解 一 堆叠注入产生原因 二 使用条件 三 堆叠注入语句 1 查看数据库 2 查看表格 3 查看列 4 查看数据 四 16进制类型 绕过 五 堆叠应用 一 堆叠注入产生原因 平常我们注入时都是通过对原来sql语句传
  • 数组元素交叉排列的算法题(a1 a2 a3 .. an b1 b2 b3 .. bn -->a 1 b1, a2 b2, a3 b3, .. an bn ) 概论思想(perfect shuffle 算法)

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