m = GCD(n, p);
for ( k = 0; k < m; k++ ) {
temp = a[k]; i = k; j = (i +p) % n;
while ( j != k ) {
a[i] = a[j]; i = j; j = ( j+p ) % n;
}
a[i] = temp;
}
}
解法三(解法二的改进型) 清航考研给出
调用子程序需要花费较多的时间和空间代价,本算法省去了计算最大公约数,仅利用一个控制变量控制循环左移的次数,效果更好。
void siftLeft_p ( int a[ ], int n, int p ) {
if ( !p ) return;
int i, j; int temp; int count = 0, k = 0;
while ( count < n ) {
i = k; temp = a[i]; j = (i+p) % n;
while ( j != k ) {
a[i] = a[j]; i = j; j = (i+p) % n;
count++;
}
a[i] = temp; count++;
k++;
}
}
设m为n与p的最大公约数,则最内层while循环执行m次,每次循环执行n/m+1次数据移动,包括与temp的相互传送2次,总的数据移动次数为m* (n/m+1) = n+m。
特别地,当p = n时,m = n,最内层while循环不执行,总的数据移动次数2n,做了n次与temp的传出和传入;当p = 0时,总的数据移动次数为0。算法用了一个附加存储temp。
解法四(被扣了分的算法)
很多考生使用了一个附加数组,先暂存子序列
{ a0, a1, ..., ap },再把序列中后面的n-p个数据元素前移,得{ ap, …, an-1 };最后把暂存到临时数组中的子序列拷贝到an-1后面,得到结果:
{ ap, …, an-1, a0, a1, ..., ap }
由于使用的附加空间较多,相应也扣了一些分。算法移动元素的次数为n+p;特别地,当n = p 时,算法移动元素的次数为2n。