• 实验案例2-2:数组元素循环右移问题


              1008 数组元素循环右移问题 (20分)

    一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(0)个位置,即将A中的数据由(A0​​A1​​AN1​​)变换为(ANM​​AN1​​A0​​A1​​ANM1​​)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

    输入格式:

    每个输入包含一个测试用例,第1行输入N(1N100)和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 }
  • 相关阅读:
    一些关于"虚拟交易"的有趣文章
    Windows中的消息队列:Message Queuing (MSMQ)
    ATLStyle模板 不用虚函数实现多态
    AIX 下获取系统CPU及内存的使用情况方法
    关于HPUNIX C 兼容性
    Android进阶Acticivity的启动模式
    ViewState & UpdatePanle & ReadOnly属性
    由网站构架演变说起
    '操作必须使用一个可更新的查询'解决方法
    ScriptManager & ClientScriptManager
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/9683278.html
Copyright © 2020-2023  润新知