C语言高效实现向量循环移位

2020-01-06 20:15:53于海丽

由于对元素求模各等价类的个数即为等价类中每个元素的间隔长度,因此实际在i个元素中进行iter个移位所得的等价类即为:

i×iter/lcm(n,i)=gcd(i,iter)=gcd(i,(⌈n/i⌉×β-α)×gcd(n,i)),由于i=β×gcd(n,i)可得gcd(β,⌈n/i⌉×β-α)=1

由此可知gcd(i,iter)=gcd(n,i),因此结论得证,共有cnt=gcd(n,i)个等价类,每个等价类的代表所构成的集合为{0,1,…,cnt-1}(用近世代数的术语来说,也就是旋转产生的置换群的陪集个数)。

因此上述伪码可重写为:


/*LOOPSHIFT(V,i) --gcd version*/
for cnt←0 to gcd(n,i)-1    /*n=length[V], "cnt←0 to n"means assign cnt in [0,n] */
 do temp←V[cnt]
   k←i
   for j←1 to (length[V]/gcd(n,i))-1
    do V[(k-i)%n]←V[k%n]
     k←k+i
   V[(k-i)%n]←temp

第二种方法(递归法):令V=ab(a为要移位的个数,length[a]与length[b]不一定相等),则旋转向量V实际就是交换向量ab得到ba,假定length[a]<length[b],分解向量b=αβ,使得length[a]=length[β],同样借助一个临时变量temp可实现向量a和β的交换,可得到第一次迭代之后的向量为βαa,接下来在对βα向量执行同样地交换,执行一系列交换之后最终得到向量ba,而递归最终到达不动点(fix-point)的条件即为所要交换的两个向量长度相等,即移位值为0。实际就是将原问题分解为一系列性质类似的子问题,利用分治的思想逐个击破,最终达到整体交换的目标。

以上方法的伪码实现为:


/*LOOPSHIFT(V,i) --recurrence version*/
//RECSHIFT(V, i, low, high)   /*low:lower_bound high:higher_bound*/
if low=high || high<i      /*i is a fix value*/
 then return            
if i-low>high-i+1         /*select a min value as the count of reversion*/
 then revcnt←high-i+1
    flag←1          /*set the flag value low bound increase*/
 else revcnt←i-low
for j←0 to revcnt-1  /*swap the elem in the vector i times*/
 do temp←V[low+j] 
   V[low+j]←V[high+1+j-revcnt]
   V[high+1+j-revcnt]←temp
if flag=1
 then low←low+revcnt
 else high←high-revcnt
RECSHIFT(V,i,low,high)  /*call itself*/