一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A0A1⋯AN−1)变换为(AN−M⋯AN−1A0A1⋯AN−M−1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
输入格式:
每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0);第2行输入N个整数,之间用空格分隔。
输出格式:
在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。
输入样例:
6 2
1 2 3 4 5 6
输出样例:
5 6 1 2 3 4
1.C++方法,利用rotate函数
rotate(beg, mid, end),该函数接受三个迭代器, 将迭代器所在的容器的元素循环移动,使得mid元素成为首元素,随后是mid + 1到end之前的元素,
再接着是beg到mid 之间的元素,返回一个迭代器,指向原来在beg位置的元素
rotate_copy(beg, mid, end, dest),即将变换过后的元素保存在目的容器的dest位置
1 #include <iostream>
2 #include <algorithm>
3 #include <vector>
4
5 using namespace std;
6
7 int main()
8 {
9 int N, M, i;
10 vector<int> vec;
11 cin >> N >> M;
12 int mount = N;
13 while (mount--)
14 {
15 cin >> i;
16 vec.push_back(i);
17
18 }
19 rotate(vec.begin(), vec.end() - (M % N), vec.end()); //循环右移
20 //rotate(vec.begin(), vec.begin() + (M % N), vec.end()); //循环左移
21 vector<int>::const_iterator iter;
22 for (iter = vec.begin(); iter != vec.end() - 1; ++iter)
23 cout << *iter << " ";
24 cout << *iter << endl;
25 return 0;
26 }
2.C的一般方法:
先写一个循环右移一位的函数,然后调用该函数M次, 即可使数组循环右移M位
1 #include <stdio.h>
2 #define MAXN 100
3
4 void CircleMove(int *array, int N);
5
6 int main()
7 {
8 int Number[MAXN], N, M;
9 int i;
10 scanf_s("%d %d", &N, &M);
11 for (i = 0; i < N; i++)
12 {
13 scanf_s("%d", &Number[i]);
14 }
15 M %= N; //当M大于等于N时转化成等价的小于N的数
16 for (i = 0; i < M; i++) //调用移位函数M次
17 CircleMove(Number, N);
18 for (i = 0; i < N -1; i++)
19 printf("%d ", Number[i]);
20 printf("%d", Number[i]);
21 return 0;
22 }
23
24 void CircleMove(int *array, int N)
25 {
26 int i, ArrayEnd;
27 ArrayEnd = array[N - 1]; //先最后一个元素记录下来,因为待会会被覆盖掉
28 for (i = N -1; i > 0; i--)
29 array[i] = array[i - 1];
30 array[0] = ArrayEnd;
31 }
3.C的简单解法
先用宏定义define 定义一个两个数相交换的的函数,该函数利用了三次异或运算符
异或运算符有一个性质,假如 a ^ b = c;那么 a ^ c = b; b ^ c = a;
#define Swap(a, b) a^ = b, b ^= a, a ^= b; //交换两个数的宏定义函数,
对这个函数的解读:
a ^= b 就是 a = a ^ b,此时a 等于上面说的C
b ^= a,就是 b = b ^ a,注意,这里的a 已经变成C了,所以相当于 b = b ^ C ---> b = a;
同理,a ^= b,就是 a = a ^ b,需要注意的是,等式右边的a在第一步变换中变成了C,b 在第二步变换中变成了a, 所以这个等式就相当于a = C ^ a ------> a = b;
所以就完成了交换。
接下来程序中利用三次逆转,实现了循环右移M位,(这种方法很神奇)
第一次:逆转整个数组
第二次:在第一步的基础上逆转数组前M个元素
第三次: 逆转数组后N- M个元素
(Swap()函数可以直接按使用algorithm 中已经有的swap()函数,效果是一样的。)
1 #include <stdio.h> 2 #define MAXN 100 3 #define Swap(a, b) a^= b, b^= a, a ^= b; //通过连续三次以后运算符交换a与b 4 5 void RightShift(int array[], int N, int M); 6 7 int main() 8 { 9 int Number[MAXN], N, M; 10 int i; 11 scanf_s("%d %d", &N, &M); 12 for (i = 0; i < N; i++) 13 scanf_s("%d", &Number[i]); 14 M %= N; 15 RightShift(Number, N); 16 for (i = 0; i < N - 1; i++) 17 printf("%d", Number[i]); 18 printf("%d", Number[N - 1]); 19 return 0; 20 } 21 22 void RightShift(int array[], int N, int M) 23 { 24 int i, j; 25 if (M > 0 && M < N) 26 { 27 for (i = 0, j < N - 1; i < j; i++, j--) //逆转N个数据 28 Swap(array[i], array[j]); 29 for (i = 0, j < M - 1; i < j; i++, j--) //逆转前M个数据 30 Swap(array[i], array[j]); 31 for (i = M, j = N - 1; i < j; i++, j--) //逆转后N - M个数据 32 Swap(array[i], array[j]); 33 } 34 }
逆转函数可以使用头文件 algorithm 中的 reverse()函数,这个函数可以将给定数组区间或迭代器区间的内容反转,使用方法是:reverse(a, a + 4); 加上a是数组,所以上面方法三的代码可以进一步得到简化:(使用这个头文件必须包含using namespace std这个命名空间)
1 #include <stdio.h> 2 #include <algorithm> 3 using namespace std; 4 5 int arr[110] = { 0 }; 6 7 int main() 8 { 9 int n, m; 10 scanf("%d %d", &n, &m); 11 for (int i = 0; i < n; i++){ 12 scanf("%d", &arr[i]); 13 } 14 m %= n; // 修正m的值 15 reverse(arr, arr + n); // 反转 0 - n之间的数字 16 reverse(arr, arr + m); // 反转 0 - (m-1)之间的数字 17 reverse(arr + m, arr + n); // 反转 m - (n-1)之间的数字 18 19 for (int i = 0; i < n; i++){ 20 if (i > 0) 21 printf(" "); 22 printf("%d", arr[i]); 23 } 24 return 0; 25 }
4 . 利用n和m的最大公约数(这个方法还不是很理解)
从N - M为开始移动,一直到(n - m + d), d 是 m 和 n 的最大公约数。每次将当前元素存储在一个临时变量上,然后将(i - M)位的元素移动到当前位置,直到(i- M) == (i + M) % N,此时将临时变量上的元素放置到该位置上,进入下次循环
1 int ans[110]; 2 3 int gcd(int a, int b){ 4 return !b ? a : gcd(b, a % b); 5 } 6 7 int main() 8 { 9 // 读取输入 10 freopen("in.txt", "r", stdin); 11 int n, m; 12 int temp, pos, next; 13 scanf("%d %d", &n, &m); 14 for (int i = 0; i < n; i++){ 15 scanf("%d", &ans[i]); 16 } 17 18 m %= n; // 修正m 19 20 // 如果m == 0,则不用移动,m != 0才需移动 21 if (m != 0){ 22 int d = gcd(m, n); 23 for (int i = n - m; i < n - m + d; i++){ 24 // 每次将当前元素存储在一个临时变量上 25 temp = ans[i]; 26 27 // 然后将(i - M)位的元素移动到当前位置, 直到(i- M) == (i + M) % N 28 pos = i; 29 do{ 30 // 计算下一个要处理的位置 31 next = (pos - m + n) % n; 32 // 如果下一个位置不是初始点 33 // 则把下一个位置的元素赋值给当前处理位置 34 if (next != i) 35 ans[pos] = ans[next]; 36 else 37 ans[pos] = temp; 38 pos = next; 39 } while (pos != i); 40 } 41 } 42 43 // 输出数组 44 for (int i = 0; i < n; i++){ 45 printf("%d", ans[i]); 46 if (i < n- 1) 47 printf(" "); 48 } 50 51 fclose(stdin); 52 return 0; 53 }