问题分析
输入:目标数组,旋转位数。
处理:将目标数组旋转指定的位数。
约束:无
解答思路
见P13页底部,一种类似杂技演员表演的移动元素的技巧。
PS:控制每次" 杂技 "的结束是实现这个算法的关键所在,也是回答本题的第二问,请参考下面代码的注释部分。
代码实现
1 #include <iostream> 2 3 using namespace std; 4 5 // 数组旋转函数 6 void rotate(int *array, int n, int r); 7 // 最大公约数函数 8 int gcd( int a, int b); 9 10 int main(void) 11 { 12 // 建立并初始化,输出测试数组。 13 int array[10]; 14 int n=10; 15 for (int i=0; i<10; i++) { 16 array[i] = i+1; 17 } 18 cout << "目标数组:" << endl; 19 for (int i=0; i<10; i++) { 20 cout << array[i] << " "; 21 } 22 cout << endl; 23 24 // 获取旋转位数 25 int r; 26 cout << "旋转位数:"; 27 cin >> r; 28 29 // 处理旋转位数 30 if (r<0) { 31 cout << "非法的旋转位数" << endl; 32 return 0; 33 } 34 else 35 r %= n; 36 37 // 调用数组旋转函数 38 rotate(array, n, r); 39 40 // 打印旋转结果 41 cout << endl << "旋转后的数组:" << endl; 42 for (int i=0; i<10; i++) { 43 cout << array[i] << " "; 44 } 45 cout << endl; 46 47 return 0; 48 } 49 50 void rotate(int *array, int n, int r) { 51 // 数组长度 n 和旋转位数 r 的最大公约数就是需要置换的轮次数 52 // 或者理解为表演杂技的" 次数 " 53 int d = gcd(r, n); 54 55 for (int i=0; i<d; i++) { 56 // t 暂存旋转操作的首元素 57 int t = array[i]; 58 59 // 每个轮次的操作 60 int j = i; 61 while ( (j+r)%n != i ) { 62 array[j] = array[(j+r)%n]; 63 j = (j+r)%n; 64 } 65 66 // 将 t 中暂存元素放回数组 67 array[j] = t; 68 } 69 } 70 71 int gcd( int a, int b ){ 72 return b==0 ? a : gcd(b, a%b); 73 }
运行测试
小结
这个算法很不错,不需要特别的空间,消耗的时间也不多。
但需要记住 n 和 r 的最大公约数的求法。