移动数组内元素的3+1个方法(附加一个开挂的方法),数据移动次数逐个变少(c++)!!!

前情提要:n为数组长度,m数组元素向右移动位数,num[n]为待移动数组。

1.适用于特殊情况的开挂方法

可用于数组的数据需要实时输入,不是在代码中写好的情况
/该方法实质上不是移动数组中的元素,而是在输入元素时进行了错位输入,
使其在输入时就已经按需要的顺序排好了,但实际上应该通过将已知数组的
元素进行移动来实现(每个数组元素移动0次)
/

#include<iostream>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    m=m%n;
    int num[n]={0};
    for(int i=m;i<n;i++){
        cin>>num[i];
    }
    for(int i=0;i<m;i++){
        cin>>num[i];
    }
    for(int i=0;i<n;i++){
        cout<<num[i];
        if(i!=n-1)
        cout<<' ';
    }    
}

2.适用于任何情况的三种方法

2.1 方法一(每个数据移动m次)

方法一:一次右移一位,一共m次循环,移动m位

void move_1(int n,int m,int num[]){
    for(int i=0;i<m;i++){
       int temp=num[n-1];
       for(int j=0;j<n-1;j++){
          num[n-1-j]=num[n-1-j-1];
       }
       num[0]=temp;
    }
}

2.2 方法二(每个数据约移动2次)

方法二:前面n-m位翻转,后m位翻转,最后整体翻转

void reversal(int start,int end,int num[]){
   int time=(end-start+1)/2;
   for(int i=0;i<time;i++){
      int temp=num[start+i];
      num[start+i]=num[end-i];
      num[end-i]=temp;
   }
}
void move_2(int n,int m,int num[]){
   reversal(0,n-m-1,num);
   reversal(n-m,n-1,num);
   reversal(0,n-1,num);
}

2.3 方法三(每个数据移动1次)

方法三:先根据“m、n的奇偶”和“m与n/2的关系“进行分类,
(1)n是奇数,m是奇数,m>n/2
(2)n是奇数,m是奇数,m<n/2
(3)n是奇数,m是偶数,m>n/2
(4)n是奇数,m是偶数,m<n/2
(5)n是偶数,m是奇数,m>n/2
(6)n是偶数,m是奇数,m<n/2
(7)n是偶数,m是奇数,m=n/2
(8)n是偶数,m是偶数,m>n/2
(9)n是偶数,m是偶数,m<n/2
(10)n是偶数,m是偶数,m=n/2
各代入一个实例后,总结出可以分为三类
(1)123456为一类,需要一次循环
(把该数组看成一个首位相连的循环队列,先取出数组最后一位即下标为n-1,
在依次把前面的第n-1-m位放到取出的空位置上,
再依次去取前面对应的那位放到已经空出的位置上,直到再次遇到下标n-1则停
止,完成一次循环即可)
(2)8和9为一类,需要2次循环(偶数位上的数和奇数位上的数各进行上面这
类的循环一次)
(3)7和10为一类,需要m次循环(前面m个元素和后面m个元素进行对应的交换)

void move_3(int n,int m,int num[]){
      //n%2==0&&n/2==m,循环m次
      if(n%2==0&&n/2==m){
         //cout<<1<<endl;
      for(int i=1;i<=m;i++){
      int temp=num[n-i]; //先取出最后一位数
      num[n-i]=num[n-i-m];
      num[n-i-m]=temp;
      }
      }
      //n%2==0&&m%2==0&&m!=n/2,循环2次
      else if(n%2==0&&m%2==0&&m!=n/2){
         //cout<<2<<endl;
      for(int i=0;i<2;i++){
      int temp=num[n-1-i]; //先取出最后一位数
      int flag=n-1-i;
      if(flag-m<0)
      flag=flag+n-m;
      else 
      flag=flag-m;
      while(flag!=(n-1-i)){
         if(flag+m>n-1-i)
         num[flag+m-n]=num[flag];
         else
         num[flag+m]=num[flag];
         if(flag-m<0)
         flag=flag+n-m;
         else
         flag=flag-m;
      }
      if(flag+m>n-1-i)
         num[flag+m-n]=temp;
         else
         num[flag+m]=temp;  
      }
      }
      //循环1次
      else{
         //cout<<3<<endl;
      int temp=num[n-1]; //先取出最后一位数
      int flag=n-1;
      if(flag-m<0)
      flag=flag+n-m;
      else 
      flag=flag-m;
      while(flag!=(n-1)){
         if(flag+m>n-1)
         num[flag+m-n]=num[flag];
         else
         num[flag+m]=num[flag];
         if(flag-m<0)
         flag=flag+n-m;
         else
         flag=flag-m;
      }
      if(flag+m>n-1)
         num[flag+m-n]=temp;
         else
         num[flag+m]=temp;  
      }
}

3.测试

#include<iostream>
using namespace std;
int main()
{
   int n,m;
    cin>>n>>m;
    m=m%n;
    int num[n]={0};
    for(int i=0;i<n;i++){
        cin>>num[i];
    }
    move_1(n,m,num);//更改此处测试方法一二三
    for(int i=0;i<n;i++){
        cout<<num[i];
        if(i!=n-1)
        cout<<' ';
    } 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值