设向量x长度为L,要将前N位循环左移。
设待移动的初始位为i,则杂技法是x[i] <->x[i+N] <-> x[i+2N] ….. <-> x[i+kN] ,当(i+kN)%L ==i时,不再移位,并将x[i+kN] = x[i] 此时完成一次移位。设L与N的最大公约数为d,则共需要完成d次移位后,才能完成了前N位的循环左移。
想要证明这种方法的可行性,也就是证明这种方法是否完成了所有位的循环左移N位。
1、设当前位为i,则第(i+N)%L将循环左移到第i位,(在此,可将向量作为一个首尾相连的圆环来理解,参考图1)
2、如何证明一共移了L位呢?
证明:在进行d次移位后,可完成前N位的循环左移,考虑每次移位移动了多少位。设L=αd,N=βd,则由于每次移位在(i+kN)%L ==i时结束,设i+kN = mL +i,则 kβd = mαd,由于α和β互素,则k ==α时,是使得等式成立的最小值,这就证明了每一次移位移动了α位后结束。只有在进行d次移位后,才能让所有L =αd位循环左移。
3、如何证明每一次移位不会对之前所移的位产生影响呢?
证明:这分为两种情况进行证明
(1)在一次移位中,不存在一个位被两次操作的情况,也就是证明(i+kN)%L == i可在一次移位中发生两次。在2中已证明,想要使得等式成立,至少需要移位α次,由此可证在一次移位中,不可能出现二次操作已被操作的位的情况。
(2)多次移位中,不存在已操作的位被再次操作的情况。证明如下:
设从0开始,进行第一次移位,即i=0时,则 x[0]ß x[0+N]、x[0+N] ß x[(0+2N)%L]
…… x[(0+(α-1)N)%L] ß x[0] 在第一次移位中,不会影响1、2、3、4……d-1 及其倍数位,证明如下:设kN%L = x … r 则 kN = xL +r 即kβd– xαd = r => (kβ – xα)d = r
由此证明,r只能是d的倍数,不可能是1、2、3、4……d-1 及其倍数。
当第一次结束时,i=i+1 =1 ,进行下一次循环,同理也可证,移位操作时,不会影响0、2、3、
4……d-1 及其倍数位,当i=d-1执行完时,移位结束,这时共移了αd位。
到此为止 证明结束
图1
实现代码1:
int* vector_loop1(int* array,int len,int loop_num)
{
int i=0,j=0,temp;
int d = gcd(len,loop_num);
while(d)
{
temp = array[i];
while((i+loop_num)%len != j)
{
array[i] = array[(i+loop_num)%len];
i = (i+loop_num)%len;
}
array[i] = temp;
j++;
i=j;
d--;
}
return array;
}
实现代码2
int* vector_loop2(int* array,int len,int loop_num)
{
int i=0,j=0,temp;
temp = array[i];
for(int k=0;k<len;k++)
{
if((i+loop_num)%len == j)
{
array[i] = temp;
j++;
i=j;
}
else
{
array[i] = array[(i+loop_num)%len];
i = (i+loop_num)%len;
}
}
return array;
}
转载于:https://blog.51cto.com/speedonward/1277391
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/110044.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...