一、题目详情
问题描述:数组元素循环右移问题
一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由()变换为(
)(最后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
二、题目解析
代码:
#include <stdio.h>
#include <malloc.h>
#define LEN sizeof(struct Data)
int main()
{
/*
* n:需要移动的正整数的个数,1<=n<=100
* m:右移的次数,m>0
* sturct Data:用于存储一系列整数的结构体类型(动态链表节点)
** int x:结构体变量,用于存储整数
** struct Data *next:结构体成员变量,用于链接结构体变量
* struct Data *head, *p1, *p2:用于创建动态链表时所需的结构体指针
* temp:用于交换结构体成员变量x的临时变量
* x:通过键盘输入的整数序列中的整数,与结构体变量x相呼应
* i:循环变量
*/
int n, m, x, temp;
int i;
struct Data
{
int x;
struct Data *next;
};
struct Data *head, *p1, *p2;
//获取待移位的数字个数以及右移位的次数
scanf("%d %d", &n, &m);
//通过创建动态链表,构建需移位的数字序列
for(i=0;i<n;i++)
{
p1 = (struct Data *)malloc(LEN);
scanf("%d", &x);
p1->x = x;
if(i == 0)
head = p1;
else
p2->next = p1;
p2 = p1;
}
p2->next = NULL;
//优化移位次数,减少重复性的移位动作
while(m>n)
m -= n;
//优化移位次数,选择移位次数小的方向进行左移位or右移位
if(m>n/2)//左移n-m次
{
//暂存首位,依次左移各位,更新末位
for(i=0;i<n-m;i++)
{
p1 = head;
temp = p1->x;//暂存首位
while(p1->next)//依次左移各位
{
p2 = p1->next;
p1->x = p2->x;
p1 = p1->next;
}
p1->x = temp;//更新末位
}
}
else//右移m次
{
//依次将当前位与(换位后)首位进行对换
for(i=0;i<m;i++)
{
p1 = head;
while(p1->next)//首位与当前位互换
{
p2 = p1->next;
temp = head->x;//暂存首位
head->x = p2->x;//将当前位更新首位
p2->x = temp;//将首位更新当前位
p1 = p2;
}
}
}
//输出移位后的整数序列
p1 = head;
while(p1)
{
if(p1==head)//首位数字前不输出空格
printf("%d", p1->x);
else//其他数字前输出空格
printf(" %d", p1->x);
p1 = p1->next;
}
return 0;
}
提交结果(分数/满分):
20/20
提示:
1. 降低移位次数的思路
1) 删减重复性的移位操作,例如:n=10,m=12,等价于 n=10,m=m-n=12-10=2,即右移12次与右移2次的效果一样。代码如下:
while(m>n)
m -= n;
2) 选择合适的移位方向,例如:n=10,m=17,基于上一个思路,可以简化为:n=10,m=7,即右移7次,若改变移位方向,可以登记为左移3次,效果一样。代码如下:
if(m>n/2)//左移n-m次
{
//暂存首位,依次左移各位,更新末位
for(i=0;i<n-m;i++)
{
......
}
}
else//右移m次
{
//依次将当前位与(换位后)首位进行对换
for(i=0;i<m;i++)
{
......
}
}
2. 针对单向链表进行左移位和右移位
1) 左移位n-m次
for(i=0;i<n-m;i++)
{
p1 = head;
temp = p1->x;//暂存首位
while(p1->next)//依次左移各位
{
p2 = p1->next;
p1->x = p2->x;
p1 = p1->next;
}
p1->x = temp;//更新末位
}
2) 右移位m次
for(i=0;i<m;i++)
{
p1 = head;
while(p1->next)//首位与当前位互换
{
p2 = p1->next;
temp = head->x;//暂存首位
head->x = p2->x;//将当前位更新首位
p2->x = temp;//将首位更新当前位
p1 = p2;
}
}
关于单向动态链表的使用方法,在前面的例题中也曾使用,可参见:PAT 1004 解析