数组循环右移问题

  首先,假设我们有一个具有6个元素的数组: 1,2,3,4,5,6

现在我们要对这个数组循环右移4次,我们很直接很够推出它的结果是:3,4,5,6,1,2 。但是我们如何去实现这样一个问题呢?

  我觉得大家最容易想到的方法就是:

  step1:保存好数组中最后一个元素的值

  step2:从第一个元素到倒数第二个元素依次向右移动一个位置

  step3:然后将刚保存的值放到空出来的数组第一个位置

  虽然这个方法想起来很简单,但是它的效率却不是很高,它的时间复杂度是O(n^2)。

  现在,我再介绍一种效率较高的算法,这个算法,充分利用了模数求余的特点。

  这种算法的时间复杂度是O(n),比上一种算法效率有了很大的提高。

  它的主要实现步骤是这样的:(记移动次数为move)

  step1:初始化时,将pre_value初始化为数组的第一个元素

  step2:从某个位置A(初始时A为0)开始开始(这里的A,B......指的是数组的下标所标志的位置),将pre_value复制到临时变量temp中,位置A加上移动的次数得到新的位置

  B = A+move,

  step3:保存位置B原来的数据到pre_value中,再将变量temp中的值复制到位置B中

  step4:重复上述步骤step2,step3 N次(N为数组的长度),将所有的元素都更新到正确的位置后,就可以得到正确的移位后的数组。

  但是在这里我们要注意到这样一个问题,可能存在这样的一种情况

  例如:将数组1,2,3,4,5,6 利用上诉算法循环右移3次,得到的结果将是

  

  这里我们看到这里形成了一个只有两个元素的环,并没有包括所有的元素,所以经过推算,我们得到这样两种情况下,应该作特殊处理,

  情况一:移位次数是偶数

  情况二:数组长度%移位次数 == 0的情况

  解决的办法就是将一次移位动作划分为多次不含上述两种情况的移位动作,比如将一次偶数次的移位动作分解成先进行n-1次奇数次移位,再接着进行1次移位。

  (注意:千万要注意第二种情况的问题)

  下面就是我实现的代码:

  

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 //该函数对于数组长度为偶数且移位的次数也为偶数情况不适用,对于数组长度能整除移位次数的情况也要另加考虑
 5 //所以,对于偶数的情况,我们要分解成先移动count-1+1的组合
 6 void BufferRightShift(int buffer[],int n,int count)
 7 {
 8     int i,j;
 9     int temp,pre_value;
10     pre_value = buffer[0];
11     if(count == 0)
12         return;
13     for(i=0,j=0;i<n;i++)
14     {
15         temp = pre_value;
16         pre_value = buffer[(j+count)%n];
17         buffer[(j+count)%n] = temp;
18         j = (j+count)%n;
19     }
20 }
21
22
23 void ROR(int buffer[],int n,int count)
24 {
25     int move = count%n;
26     if((move%2 == 0)||(n%move == 0))  //存在上面分析到的两种情况自已的处理方法
27     {
28         int k = 1;
29         int i = move;
30         while(1)
31         {
32             if(i == 1)
33                 break;
34             if((i%2 == 0) || (n%i == 0))  //统计将移位次数分解成不再出现上述两种问题的次数
35                 {
36                     k++;
37                     i--;
38                 }
39             else
40                 break;
41         }
42         BufferRightShift(buffer,n,move-k);
43         for(i=1;i<=k;i++)
44             BufferRightShift(buffer,n,1);
45
46     }
47     else
48     {
49         BufferRightShift(buffer,n,move);
50     }
51 }
52
53 int main()
54 {
55     int n,count,i;
56     int *a;
57     while(scanf("%d%d",&n,&count)!=EOF)
58     {
59         a = (int*)malloc(n*sizeof(int));
60         for(i=0;i<n;i++)
61             scanf("%d",&a[i]);
62
63         ROR(a,n,count);
64
65         for(i=0;i<n-1;i++)
66         {
67             printf("%d ",a[i]);
68         }
69         printf("%d\n",a[n-1]);
70         free((void*)a);
71     }
72     return 0;
73
74 }

  运行结果:

  

  

时间: 2024-10-29 19:06:23

数组循环右移问题的相关文章

线性表(一)&mdash;&mdash;数组循环右移算法

源码:rshift.cpp #include "stdafx.h" #include <stdio.h> /************************************************************************/ /* 数组循环右移算法 */ /************************************************************************/ /* * 要求:只用一个元素大小的辅助空间

数组循环右移

Q:把一个含有 N 个元素的数组循环右移 K 位,要求时间复杂度为 O (N),且只允许使用两个附加变量. 开始的思路: 1.若k=整数倍N, 完成:k大于N,k=N%k:k小于N,开始处理. 2.tmp1保存取出的元素a[k]:a[0]放在k:tmp2保存a[2k], tmp1放入2k:tmp1保存a[3k],tmp2放入3k...直到位置[0]被放入一个新值,一轮循环完毕.这是一个从位置[0]出发,又回到位置[0]的接龙游戏. 仔细考虑下,发现,若N%k==0,则需要从[0]开始,[0]结束

(转)数组循环右移

设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量. 不合题意的解法如下: 我们先试验简单的办法,可以每次将数组中的元素右移一位,循环K次.abcd1234→4abcd123→34abcd12→234abcd1→1234abcd.伪代码如下: 代码清单2-33 RightShift(int* arr, int N, int K) { while(K--) { int t = arr[N - 1]; for(int i = N - 1; i >

习题8-3 数组循环右移(20 分)

本题要求实现一个对数组进行循环右移的简单函数:一个数组a中存有n(>0)个整数,将每个整数循环向右移m(≥0)个位置,即将a中的数据由(a?0??a?1???a?n?1??)变换为(a?n?m???a?n?1??a?0??a?1???a?n?m?1??)(最后m个数循环移至最前面的m个位置). 函数接口定义: int ArrayShift( int a[], int n, int m ); 其中a[]是用户传入的数组:n是数组的大小:m是右移的位数.函数ArrayShift须将循环右移后的数组仍

PAT 1008(数组循环右移问题)

1008 数组元素循环右移问题 (20分) 一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A?0??A?1???A?N−1??)变换为(A?N−M???A?N−1??A?0??A?1???A?N−M−1??)(最后M个数循环移至最前面的M个位置).如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法? 输入格式: 每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0):第2行输入N个整数,之间用空格分隔

【算法编程】循环右移一个数组

仅用一个辅助节点将一个大小为n数组循环右移k位的三种办法: 1.时间复杂度最大:将所有元素每次只移动一位,总共移动k次,程序实现十分容易,在此就不具体实现了. 2.时间复杂度适中:依次将每个元素都放到辅助节点上,然后将其储存到目的节点,具体程序如下: #include<iostream> using namespace std; int gcd(int x,int y); int main() { int n,k; cout<<"请输入数组的维数"<<

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

1008. 数组元素循环右移问题 (20) 一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0 A1--AN-1)变换为(AN-M -- AN-1 A0 A1--AN-M-1)(最后M个数循环移至最前面的M个位置).如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法? 输入格式:每个输入包含一个测试用例,第1行输入N ( 1<=N<=100).M(M>=0):第2行输入N个整数,之间用空格

数组的循环右移问题(好未来笔试题)

问题描述:给定一个整数数组,长度为n,现在要求该数组循环右以m个元素. 例如,数组为{1,2,3,4,5,6,7,8,9},循环右移3个元素后为变成{7,8,9,1,2,3,4,5,6} 分析:这是我曾经参加好未来笔试时的一道编程题目,考完试后,总结了以下几种解法,给大家分享下. 解法一:辅助空间法,思路很简单,就是另外开辟一块和原来数组一样大小的空间.然后先把原来数组的最后面的m个元素复制到 新数组的前面,然后再把原来数组的前面的元素复制到新数组的后面,最后再把新数组的全部元素复制到原来的数组

数组元素循环右移及静态链表

1. 静态链表 https://github.com/BodhiXing/Data_Structure/tree/master/StaticListDemo 2. 数组元素循环右移 https://pta.patest.cn/pta/test/17/exam/4/question/262 思路:不做循环,只是换方式打印输出. 1 #include <stdio.h> 2 #include <math.h> 3 4 5 int main() { 6 int n,m,i; 7 scan