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

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

问题:n个元素的向量V循环移位(以左移为例)i个位置,例如12345循环移动2个位置得到34512.

问题本身非常简单,以至于我们一看到问题就能想到对应的解决策略:申请i个字节的动态存储,将向量区间[0,i-1]的i个元素存储至临时存储器,之后将[i,n]的n-i+1个元素向左移动i个位置,并将临时存储器中的i个元素写回原向量区间中[n-i+1,n]。但如果我们强加一些限制:在现有可申请内存的总量k << i以及所要求的时间复杂度为O(n)的情况下如何实现循环移位?问题的复杂度似乎就上了一个量级。而之所以写这篇文章,很大程度上是因为接下来要介绍的三种方法带来了对问题本质更深入的思考。

方法一(姑且称之为求模法):借助一个临时变量temp,temp ← V[0],V[0] ← V[i%n],V[i%n] ← V[(2i)%n]…直到(ki)%n =0时,此时所要完成的操作即为V[((k-1)i)%n] ← V[0],而由于变量V[0]的值在被V[i%n]覆盖之前已存入temp,取而代之的操作即为:V[((k-1)i)%n] ← temp。图解表示为(图示的移位个数为i=3):

C语言,向量循环,移位

整个操作过程借助一个临时变量,经过n次左右的操作即完成整个移位过程,时间复杂度满足O(n)。事实上,向量中所有的元素都进行了移位操作,因此如果当完成V[((k-1)i)%n] ← temp操作时,仍有元素未完成移动,此时从V[1]开始再次进行移动。因为如果没有移动全部的元素,则说明最初的i个元素将分为m(m>1)个等价类,所以从V[1]开始再次移动是可行的,这归功于等价类的性质:任何求模等价类聚集中每个集合中的每个元素间隔的长度相等。所以若0和1同属一个等价类,则该等价类必然包含所有i个元素。

上述过程的伪码表示为: