PAT 1008 解析


一、题目详情


问题描述:数组元素循环右移问题

一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A_{0}A_{0}...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个整数,之间用空格分隔。

输出格式:

在一行中输出循环右移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 解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值