6.求循环节
成绩 | 10 | 开启时间 | 2021年09月17日 星期五 11:25 |
折扣 | 0.8 | 折扣时间 | 2021年09月30日 星期四 23:55 |
允许迟交 | 否 | 关闭时间 | 2021年10月17日 星期日 23:55 |
对于任意的真分数 N/M ( 0 < N < M ),均可以求出对应的小数。如果采用链表存储各位小数,对于循环节采用循环链表表示,则所有分数均可以表示为如下链表形式。
输入: N M
输出: 整个循环节
要求:
编写一个尽可能高效的查找循环节起始点的函数: NODE * find( NODE * head, int * n ) 。函数的返回值为循环节的起点(即图中的指针p),n为循环节的长度。
说明:提交程序时请同时提交将分数转换为小数的函数 change( int n, int m, NODE * head ) (前面题目中已经编写)。
预设代码
前置代码
/* PRESET CODE BEGIN - NEVER TOUCH CODE BELOW */
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{ int data;
struct node * next;
} NODE;
NODE * find( NODE * , int * );
void outputring( NODE * );
void change( int , int , NODE * );
void outputring( NODE * pring )
{ NODE * p;
p = pring;
if ( p == NULL )
printf("NULL");
else
do { printf("%d", p->data);
p = p->next;
} while ( p != pring );
printf("\n");
return;
}
int main()
{ int n, m;
NODE * head, * pring;
scanf("%d%d", &n, &m);
head = (NODE *)malloc( sizeof(NODE) );
head->next = NULL;
head->data = -1;
change( n, m, head );
pring = find( head, &n );
printf("ring=%d\n", n);
outputring( pring );
return 0;
}
/* Here is waiting for you.
void change( int n, int m, NODE * head )
{
}
NODE * find( NODE * head, int * n )
{
}
*/
/* PRESET CODE END - NEVER TOUCH CODE ABOVE */
测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
---|---|---|---|---|---|
测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
测试用例 2 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
测试用例 3 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
测试用例 4 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M | 0 |
代码
这一题延申自上一题,加了一个find函数,返回循环节的结点位置
还是分为学长代码和我的代码,学长代码比较方便, 因为他在change函数中就已经采用了p1和p2两个数表示循环节的起始位置和终止位置,因此他的find函数就很简单。而我之前没有设这俩参数,只能再从头遍历一遍找循环节了……
学长代码
#include <string.h>
int p1 = 0, p2 = 0;
void change(int n,int m,NODE *head)
{
int shang[10010],yushu[10010];
memset(shang,0,sizeof(shang));
memset(yushu,0,sizeof(yushu));
p1=0,p2=0;
int flag=0;
int num=n*10;
for(int i=0;;i++)
{
shang[i]=num/m;
yushu[i]=num%m;
for(int j=0;j<i;j++)
{
if(shang[j]==shang[i]&&yushu[j]==yushu[i])
{
p1=j;
p2=i;
flag=1;
break;
}
}
num=yushu[i]*10;
if(!num)
{
p1=i+1;
break;
}
if(flag==1)
{
break;
}
}
NODE *r=head;
for(int i=0;i<p1;i++)
{
NODE *q=(NODE*)malloc(sizeof(NODE));
q->data=shang[i];
q->next=NULL;
r->next=q;
r=q;
}
if (flag == 1)
{
NODE *r1=r;
for (int i=p1;i<p2;i++)
{
NODE *q = (NODE*)malloc(sizeof(NODE));
q->data=shang[i];
q->next=NULL;
r->next=q;
r=q;
}
r->next=r1->next;
}
}
NODE *find(NODE *head,int *n)
{
if(p2>p1)
{
NODE *p=head->next;
*n=p2-p1;
for(int i=0;i<p1;i++)
{
p=p->next;
}
return p;
}
else
{
*n=0;
return NULL;
}
}
我的代码
void change(int n,int m,NODE *head){
NODE *q=(NODE*)malloc(sizeof(NODE));
q=head;
NODE *o=(NODE*)malloc(sizeof(NODE));
o=head;
int yushu[100]={0};
int shang[100]={0};
int flag=0;
int len=0;
while(n*10/m>0){
NODE *p=(NODE*)malloc(sizeof(NODE));
p->data=n*10/m;
q->next=p;
q=q->next;
shang[len]=n*10/m;
yushu[len++]=n*10%m;
n=n*10%m;
if(n==0){
q->next=NULL;
break;
}
for(int i=0;i<len-1;i++){
if(shang[i]==shang[len-1]&&yushu[i]==yushu[len-1]){
int idx=0;
while(idx<=i){
o=o->next;
idx++;
}
int idx2=0;
NODE *r=(NODE*)malloc(sizeof(NODE));
r=head;
while(idx2<len-1){
r=r->next;
idx2++;
}
r->next=o;
flag=1;
break;
}
}
if(flag==1){
break;
}
}
}
NODE *find(NODE *head,int *n){
NODE *num[100];//指针数组
int len1=0;//总长度
int len2=0;//循环节长度
int start=0;
int flag=0;
NODE *p=(NODE*)malloc(sizeof(NODE));
p=head;//不要直接用head,后面head还有用
while(p!=NULL){
num[len1++]=p;
p=p->next;
for(int i=0;i<len1-1;i++){
if(num[i]==num[len1-1]){//位置一样,注意不是数字一样,循环了
len1--;//最后一个数是循环的数,和循环节重复,要删掉
start=i;//循环开始的地方
len2=len1-start;
flag=1;
break;
}
}
if(flag==1){//找到起点了
break;
}
}
NODE *pring=(NODE*)malloc(sizeof(NODE));
if(p!=NULL){//循环的情况
pring=head;
while(start--){
pring=pring->next;//找到循环开始结点
}
*n=len2;//注意主函数中pring = find( head, &n );
//第二个参数是一个地址,因此第二个参数要作为指针指向len2
return pring;
}
else{
pring=p;//若能整除,则p为NULL
*n=0;
return pring;
}
}
这道题还是coding的问题,没什么好说的,注释写的很清楚了
写这种题先看一下主函数是怎么调用的
祝大家天天AC