主题:第36次编程比赛第1题题目
boxertony [专家分:23030] 发布于 2006-08-04 12:24:00
法雷序列:
对任意给定的一个自然数n,将分母小于等于n的不可约的真分数按升序排列,
并且在第一个分数之前加上数0/1,在最后一个分数之后加上1/1,这个序列
称为n级法雷序列,以Fn表示。例如,F8为:
0/1, 1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5,
5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8, 1/1。
请编程输出任意的Fn序列。
函数原型:
// n - 序列级数
// farey[] - 存放Fn序列,以','分隔
void FareySequence(int n, char farey[]);
例:
输入:
5
数组中存放结果为:
0/1,1/5,1/4,1/3,2/5,1/2,3/5,2/3,3/4,4/5,1/1
回复列表 (共32个回复)
11 楼
瞬间移动 [专家分:320] 发布于 2006-08-05 16:45:00
分析:
n=1: 0/1,1/1,
n=2: 0/1,1/2,1/1,
n=3: 0/1,1/3,1/2,2/3,1/1,
n=4: 0/1,1/4,1/3,1/2,2/3,3/4,1/1,
n=5: 0/1,1/5,1/4,1/3,2/5,1/2,3/5,2/3,3/4,4/5,1/1,
规律:
1: 1/2在这组分数的中间位置
2: 从1/2向两边走,每对数相加值为1
注:n=1 不满足以上规律 另行处理
代码:
#include "stdio.h"
#define N 100
/*函数申明*/
int M(int a, int b);/*返回a,b的最大公约数 */
void FareySequence( int n, char farey[] );/*将n级法雷序列存放在数组farey中*/
void main()
{
char *farey;
int n, i=0, term;
printf("输入法雷序列级数:\n");
scanf("%d", &n);
FareySequence( n, farey );
printf("\n");
while( farey[i] != '\0' )
{ //为了处理 n>=10 时的情况
if( farey[i] > '9' )
printf("%d",farey[i]-48);
else
printf("%c", farey[i]);
i++;
}
}
void FareySequence( int n, char farey[] )
{
int a[N], b[N];/*存储分子和分母*/
int i=1;/*用来计算分数个数*/
int j, k, count, x, y;
float z;
a[0]=0;
b[0]=1;/*存储第一个分数0/1*/
for( j=n; j>2; j-- )
for( k=1; k<=j/2; k++ ) /*只用排列一边的数,另一边可用规律2算出*/
{
if( M(j, k) ==1 )/*若a,b互质*/
{/*将需排列的一边的数存入a[],b[]*/
a[i]=k;
b[i]=j;
i++;
}
}
if( n==1 )
{
a[1]=1; b[1]=1;
}
else
{
a[i]=1; b[i]=2;/*存分数1/2*/
a[2*i]=1; b[2*i]=1;/*存分数1/1*/
}
/*排序*/
for( j=1; j<i; j++ )
{/*排0/1与1/2之间的数*/
x=a[j]; y=b[j];
z=1.0;
for( k=j; k<i; k++ )
{
if( z > (float)a[k]/b[k] )
{
z = (float)a[k]/b[k];
count = k;
}
}
a[j] = a[count];
b[j] = b[count];
a[count] = x;
b[count] = y;
}
/*存入另一边的数*/
for( k=1; k<i; k++ )
{/*共有0~2*i, (2*i+1)个数*/
a[i+k] = b[i-k] - a[i-k];
b[i+k] = b[i-k];
}
/*将分数存入farey[]中*/
for( k=0, j=0; k<=2*i; k++ )
{
if( n==1 && k==2 ) break;/*n=1时的不同处理*/
farey[j++] = a[k]+48; /*将数字i转换为字符'i'*/
farey[j++] = '/';
farey[j++] = b[k]+48;
farey[j++] = ',';
}
farey[j] = '\0'; /*字符串结束符*/
}
int M( int a, int b )
{
int n, t;
if( a<b )
{
t=a; a=b; b=t;
}
while( b!=0 )
{
n=a%b;
a=b;
b=n;
}
return a;
}
测试数据:
10 [enter]
0/1,1/10,1/9,1/8,1/7,1/6,1/5,2/9,1/4,2/7,3/10,1/3,3/8,2/5,3/7,4/9,1/2,5/9,4/7,3/5,5/8,2/3,7/10,5/7,3/4,7/9,4/5,5/6,
6/7,7/8,8/9,9/10,1/1,
12 楼
火海时代 [专家分:230] 发布于 2006-08-05 18:24:00
#include <iostream>
#include <math.h>
using namespace std;
bool pan(int zi, int mu)
{
int i;
int j;
if(zi>1&&mu%zi==0)
return false;
j = (int)sqrt((float)zi);
if(zi % 2 == 0) //先判断2
if(mu % 2 == 0)
return false;
for(i = 3; i <= j;i+=2) //然后判断所有奇数
if(zi % i == 0)
if(mu % i == 0)
return false;
return true;
}
void FareySequence(int n, char farey[])
{
int zi,mu;
zi = 1;
mu = n;
int len = 0;
int count = 0;
double *a;
char **b;
while(1)
{
if(zi<mu)
if(pan(zi,mu))
len++;
if(mu > 2)
mu--;
else
{
mu = n;
zi++;
}
if(zi == n)
break;
}
zi = 1;
mu = n;
a = new double[len];
b = new char*[len];
for(int i = 0; i < len; i++)
b[i] = new char[4];
while(1)
{
if(zi<mu)
if(pan(zi,mu))
{
a[count] = (double)zi/mu;
b[count][0] = zi+48;
b[count][1] = '/';
b[count][2] = mu+48;
b[count][3] = '\0';
count++;
}
if(mu > 1)
mu--;
else
{
mu = n;
zi++;
}
if(zi == n)
break;
}
for(int i = 0; i < len-1; i++)
for(int j = i+1; j < len; j++)
if(a[i] > a[j])
{
double temp = a[i];
a[i] = a[j];
a[j] = temp;
char p[4];
strcpy(p,b[i]);
strcpy(b[i],b[j]);
strcpy(b[j],p);
}
farey[0] = '0';
farey[1] = '/';
farey[2] = '1';
farey[3] = ',';
for(int i = 0; i < len; i++)
{
farey[4+i*4] = b[i][0];
farey[5+i*4] = b[i][1];
farey[6+i*4] = b[i][2];
farey[7+i*4] = ',';
}
farey[4+len*4] = '1';
farey[5+len*4] = '/';
farey[6+len*4] = '1';
farey[7+len*4] = '\0';
delete[]a;
delete[]b;
return;
}
int main(void)
{
char farey[92];
int n = 8;
FareySequence(n,farey);
cout << farey << endl;
cin.get();
return 0;
}
13 楼
liangbch [专家分:1270] 发布于 2006-08-05 20:29:00
// 36match1.cpp : Defines the entry point for the console application.
//
//#define REAL_TIME_CALC
//#define OUT_TIME
//#include "stdafx.h"
#ifdef OUT_TIME
#include "currTime.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <search.h>
typedef unsigned char BYTE;
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef int BOOL;
#define TRUE 1
#define FALSE 0
#define FAREY_BASE 1000
#define FRACTION_ARRAY_BASE 64
typedef struct _PrimeTab
{
DWORD *PrimeTab;
BYTE *byteFlag;
int max;
int count;
}PrimeTab;
typedef struct _Fraction
{
#ifndef REAL_TIME_CALC
double value;
#endif
WORD numerator;
WORD denominator;
}Fraction;
typedef struct _FractionArray
{
Fraction *Data;
int size;
int count;
}FractionArray;
typedef struct _FareyArray
{
BYTE *pByteArray;
int byteArrayLen;
int fac_count;
DWORD fac[32];
FractionArray array;
}FareyArray;
// 全局变量,质数表
PrimeTab g_primeTab=
{
NULL,
NULL,
0,
0
};
FareyArray g_fareyArray;
//将n转化为字符串str,不写入字符串结束符0
//如果不考虑性能,可用sprintf(str,"%d",n)来实现类似的功能
char* my_itoa(int n,char *str)
{
char buff[12];
char *p=buff+11;
if (n==0)
{
*str++='0';
return str;
}
*p--=0;
while (n>0)
{
*p-- = (n % 10)+'0';
n/=10;
}
p++;
while (*p)
*str++= *p++;
return str;
}
//扩大动态数组的存储空间
//形如FractionArray_实现动态数组的部分功能
//在C++中,可以用直接使用 STL中的 vector
BOOL FractionArray_setSize(FractionArray *me,int newSize)
{
if ( newSize < me->size || newSize==me->size)
return FALSE;
Fraction *p=new Fraction[newSize];
if (p==NULL)
return FALSE;
//--------------------
if ( me->Data!=NULL)
{
memcpy(p,me->Data,sizeof(Fraction)*me->size);
delete[] me->Data;
}
me->Data=p;
me->size=newSize;
return TRUE;
}
//形如FractionArray_实现动态数组的部分功能
//在C++中,可以用直接使用 STL中的 vector
//将n添加到动态数组中
BOOL FractionArray_Append(FractionArray *me,Fraction n)
{
BOOL bRet=TRUE;
if ( me->count == me->size)
{
int newSize= (me->size + me->size/4+256-1) >> 8;
newSize <<=8 ;
bRet=FractionArray_setSize(me,newSize);
}
if (!bRet)
{
printf("No enough memory\n");
return bRet;
}
me->Data[me->count]=n;
me->count++;
return TRUE;
}
static int __cdecl FractionCompare(const void *element1,const void *element2)
{
Fraction *p1,*p2;
p1=(Fraction *)element1;
p2=(Fraction *)element2;
#ifdef REAL_TIME_CALC
double v1,v2;
v1=(double)(p1->numerator) / (double)(p1->denominator);
v2=(double)(p2->numerator) / (double)(p2->denominator);
if ( v1 > v2)
return 1;
else if ( v1 < v2 )
return -1;
else
return 0;
#else
if ( (p1->value) > (p2->value))
return 1;
else if ( (p1->value) < (p2->value))
return -1;
else
return 0;
#endif
}
//使用c库函数qsort(快速排序对分数数组排序)
void FractionArray_Sort(FractionArray *me)
{
qsort( me->Data, (size_t)me->count, sizeof( Fraction), FractionCompare );
}
//输出分数数组的所有分数到buff,各个分数用/来隔开
void FractionArray_output(FractionArray *me,char buff[] )
{
int i;
char *tag;
for (tag=buff,i=0;i<me->count-1;i++)
{
tag=my_itoa( me->Data[i].numerator,tag);
*tag++='/';
tag=my_itoa( me->Data[i].denominator,tag);
*tag++=',';
}
i=me->count-1;
tag=my_itoa( me->Data[i].numerator,tag);
*tag++='/';
tag=my_itoa( me->Data[i].denominator,tag);
*tag=0;
}
//形如FractionArray_实现动态数组的部分功能
//在C++中,可以用直接使用 STL中的 vector
//释放分数数组所占用的内存空间
void FractionArray_Free(FractionArray *me)
{
if (me->Data!=NULL)
delete[] me->Data;
me->Data=NULL;
me->count=0;
me->size=0;
}
//形如FractionArray_实现动态数组的部分功能
//在C++中,可以用直接使用 STL中的 vector
//初始化分数数组,预留FRACTION_ARRAY_BASE个元素空间
void FractionArray_Init(FractionArray *me)
{
me->Data=NULL;
me->count=0;
me->size=0;
FractionArray_setSize(me,FRACTION_ARRAY_BASE);
}
14 楼
liangbch [专家分:1270] 发布于 2006-08-05 20:44:00
//接上页
// 用埃氏筛法计算n以内的所有质数
//sift the all prime less than n
void PrimeTab_Sift(BYTE *siftbuff,DWORD n)
{
DWORD i,sqrt_n,p;
//----------------------------
sqrt_n=(int)sqrt(n)+1;
while (sqrt_n*sqrt_n >n)
sqrt_n--;
memset(siftbuff,1,n+1);
*siftbuff=0;
*(siftbuff+1)=0; //1不是质数
*(siftbuff+2)=1; //2是质数
for (i=4;i<=n;i+=2)
*(siftbuff+i)=0; //筛去2的倍数
for (i=3;i<=sqrt_n;) //i 是质数
{
for (p=i*i;p<=n; p+=2*i)
*(siftbuff+p)=0; //筛去i 的奇数倍
i+=2;
while ( *(siftbuff+i)==0 )
i++; //前进到下一个质数
}
}
//初始化n以内的质数表,
//如果质数的范围小于n,则用埃氏筛法重新筛选质数
BOOL PrimeTab_ReSift(PrimeTab *pTab,DWORD n)
{
int i,count1,count2;
if ( n<=pTab->max)
return TRUE;
if (pTab->byteFlag!=NULL)
{
delete[] pTab->byteFlag;
pTab->byteFlag=NULL;
}
if (pTab->PrimeTab!=NULL)
{
delete[] pTab->PrimeTab;
pTab->PrimeTab;
}
pTab->byteFlag=new BYTE[n+1];
if (pTab->byteFlag==NULL)
return FALSE;
PrimeTab_Sift(pTab->byteFlag,n);
//统计n以内的所有质数的个数
for (count1=0,i=0;i<=n;i++)
{
if (pTab->byteFlag[i])
count1++;
}
pTab->PrimeTab=new DWORD[count1];
//将筛出来的质数放入质数表
count2=0;
for (i=0;i<=n;i++)
{
if (pTab->byteFlag[i])
{
pTab->PrimeTab[count2]=i;
count2++;
}
}
pTab->max=n;
pTab->count=count2;
return TRUE;
}
//释放FareyArray变量占用的内存空间
BOOL Farey_Free(FareyArray *p)
{
if (p->pByteArray!=NULL)
{
delete[] p->pByteArray;
p->pByteArray=NULL;
}
p->byteArrayLen=0;
FractionArray_Free(&(p->array));
return TRUE;
}
//为本程序分配所需的内存空间,仅需在main开始时调用一次
BOOL InitData()
{
g_fareyArray.byteArrayLen=0;
g_fareyArray.pByteArray= new BYTE[FAREY_BASE+1];
if (g_fareyArray.pByteArray==NULL)
return FALSE;
g_fareyArray.byteArrayLen=FAREY_BASE;
FractionArray_Init( &(g_fareyArray.array));
return TRUE;
}
//释入为本程序分配所需的内存空间,仅需在main结束时时调用一次
void FreeData()
{
if (g_primeTab.PrimeTab!=NULL)
delete[] g_primeTab.PrimeTab;
if (g_primeTab.byteFlag!=NULL)
delete[] g_primeTab.byteFlag;
g_primeTab.count=0;
g_primeTab.max =0;
g_primeTab.PrimeTab=NULL;
g_primeTab.byteFlag=NULL;
Farey_Free(&g_fareyArray);
}
//为计算法雷序列分配内存空间
BOOL Farey_Init(FareyArray *p,int n)
{
if (n< p->byteArrayLen && p->pByteArray!=NULL)
return TRUE;
p->byteArrayLen=0;
p->pByteArray= new BYTE[n+1];
if (p->pByteArray==NULL)
return FALSE;
p->byteArrayLen=n;
FractionArray_Init( &(p->array));
return TRUE;
}
// 判断n 是否是质数,是返回1,否,将素因子存入p->fac
int Farey_isPrime( int n,
FareyArray *p,
PrimeTab *primeTab
)
{
int flag,t,i=0;
p->fac_count=p->fac[0]=0;
if ( primeTab->byteFlag[n] )
return TRUE;
i=0;
while (n>1 && i<primeTab->count)
{
t=primeTab->PrimeTab[i];
if ( t*2>n)
break;
flag=0;
while ( n % t==0 )
{
n /=t;
flag=1;
}
if ( flag)
{
p->fac[p->fac_count]=t;
p->fac_count++;
}
if ( primeTab->byteFlag[n] )
{
p->fac[p->fac_count]=n;
p->fac_count++;
break;
}
i++;
}
return FALSE;
}
15 楼
liangbch [专家分:1270] 发布于 2006-08-05 20:50:00
//将分母为n的最简分数,添加到数组pFareyArray中去
BOOL AddToFractionArray(int n,FareyArray *pFareyArray,PrimeTab *pPrimeTab)
{
BOOL bIsPrime,bRet;
int j,j1,j2,t;
Fraction frac;
bIsPrime=Farey_isPrime(n,pFareyArray,pPrimeTab);
if ( bIsPrime)
{
for (j=1;j<n;j++)
{
frac.numerator=j;
frac.denominator=n;
#ifndef REAL_TIME_CALC
frac.value= (double)frac.numerator / (double)frac.denominator;
#endif
bRet=FractionArray_Append(&(g_fareyArray.array),frac);
if (!bRet)
return bRet;
}
}
else
{
memset( g_fareyArray.pByteArray,0,g_fareyArray.byteArrayLen);
//筛去和分母不互质的所有分子
for (j1=0;j1<g_fareyArray.fac_count;j1++)
{
t=g_fareyArray.fac[j1];
for (j2=t;j2<n;j2+=t)
g_fareyArray.pByteArray[j2]=1;
}
for (j1=1;j1<n;j1++)
{
//仅仅将和n(分母)互质的数组成的分数添加到分数数组
if (g_fareyArray.pByteArray[j1]==0)
{
frac.numerator=j1;
frac.denominator=n;
#ifndef REAL_TIME_CALC
frac.value= (double)frac.numerator / (double)frac.denominator;
#endif
bRet=FractionArray_Append(&(g_fareyArray.array),frac);
if (!bRet)
return bRet;
}
}
}
return TRUE;
}
//按照比赛要求编写的函数,首次调用时FareySequence,需调用InitData,
//再次调用时,不需要调用InitData,参见测试函数main
//对n没有算法上的限制,实际上对n的主要限制来自主存容量,
//在调用这个函数时,需要分配一块内存用于存储字符串,这需要很大的内存空间,
//根据我的测试经验,大概需n*n*3 字节,我的测试程序中,这个值取n*n*4,
//当n较小时,(在我的计算机,内存256M,n<4000左右时),不需要虚拟内存,速度很快,
//当n更大时,(在我的计算机,n>5000左右),则使用虚拟内存,速度变慢
//当n大于一定程度(在我的计算机上,n=7000 可工作,更大的n没有测试),虚拟内存也会不足,
//则这个函数不能工作
void FareySequence(int n,char farey[])
{
int i,sqrt_n;
double t1,t2,t3;
Fraction frac;
BOOL bRet;
//----------------------------------
farey[0]=0;
bRet=PrimeTab_ReSift(&g_primeTab,n);
if (!bRet)
return;
if (!Farey_Init(&g_fareyArray,n))
return ;
#ifdef OUT_TIME
t1=currTime();
#endif
for (i=2;i<=n;i++)
{
//printf("i=%d\n",i);
bRet=AddToFractionArray(i,&g_fareyArray,&g_primeTab);
if (!bRet)
return;
}
#ifdef OUT_TIME
t1=currTime()-t1;
#endif
frac.numerator=0;
frac.denominator=1;
#ifndef REAL_TIME_CALC
frac.value= 0.00;
#endif
FractionArray_Append(&(g_fareyArray.array),frac);
frac.numerator=1;
frac.denominator=1;
#ifndef REAL_TIME_CALC
frac.value= 1.00;
#endif
FractionArray_Append(&(g_fareyArray.array),frac);
#ifdef OUT_TIME
t2=currTime();
#endif
FractionArray_Sort(&(g_fareyArray.array));
#ifdef OUT_TIME
t2=currTime()-t2;
t3=currTime();
#endif
FractionArray_output(&(g_fareyArray.array),farey);
#ifdef OUT_TIME
t3=currTime()-t3;
#endif
FractionArray_Free(&(g_fareyArray.array));
FractionArray_Init(&(g_fareyArray.array));
#ifdef OUT_TIME
printf("calc time=%.12f s\nSort time=%.12f s\noutput time=%.12f s\n",t1,t2,t3);
#endif
}
int main(int argc, char* argv[])
{
int n;
char *pBuff=NULL;
char name[32];
FILE *fp=NULL;
InitData();
while (1)
{
printf("n=?");
scanf("%d",&n);
if (n==0)
break;
pBuff=new char[n*n*4+4096];
if (pBuff==NULL)
return 0;
FareySequence(n,pBuff);
sprintf(name,"%d.txt",n);
fp=fopen(name,"wt");
fwrite(pBuff,1,strlen(pBuff),fp);
fclose(fp);
delete[] pBuff;
}
FreeData();
return 0;
}
//测试表明,qsort函数是瓶颈,我将提交另一个程序,再次提高速度。
16 楼
zheni [专家分:60] 发布于 2006-08-05 21:41:00
void FareySequence(int n,char farey[]){
#define NULL 0
struct fs{
int a,b;
struct fs *next;
};
struct fs *fs_start,*fs_end,*p,*l,*r,*m;
int i,size;
size=sizeof(struct fs);
fs_start=(struct fs *)malloc(size);
fs_end=(struct fs *)malloc(size);
fs_start->a=0;
fs_start->b=1;
fs_start->next=fs_end;
fs_end->a=1;
fs_end->b=1;
fs_end->next=NULL;
for(i=1;i<n;i++){
l=fs_start;
r=l->next;
do{
if ((l->a+r->a)<n&&(l->b+r->b)<=n){
m=(struct fs *)malloc(size);
m->a=l->a+r->a;
m->b=l->b+r->b;
m->next=r;
l->next=m;
}
l=r;
r=r->next;
}while(r!=NULL);
}
m=fs_start;
i=0;
do{
farey[i++]=m->a+48;
farey[i++]='/';
farey[i++]=m->b+48;
farey[i++]=',';
m=m->next;
}while(m->next!=NULL);
farey[i++]=m->a+48;
farey[i++]='/';
farey[i++]=m->b+48;
}
如果n大于9我就没有好的办法把他们放到数组中了。
17 楼
kakaguilai [专家分:0] 发布于 2006-08-05 22:52:00
kan kan
18 楼
kakaguilai [专家分:0] 发布于 2006-08-05 22:53:00
看看大家怎么写
19 楼
wshong [专家分:1880] 发布于 2006-08-06 00:44:00
看看。。。。
20 楼
hyerty [专家分:1110] 发布于 2006-08-06 06:50:00
偶是第一次来参加,所以准备了好久,写了又写,改了又改,换了好几个版本了,现在终于定稿了,有不合规则的地方请多包含。
先说一下我的思路,我是用结构体表示分数,然后用链表来储存生成的法雷序列。法雷序列存在性质:对任意三项a/b,c/d,e/f有(a+e)/(b+f)=c/d(这个规律从网上搜出来的,不犯规吧?),所以我先给出第一项0/1和最后一项1/1,然后用此性质来生成中间的项。先用前两项生成他们中间一项,再用新的前两项继续生成他们中间的项,直到生成的分数化为最简后分母大于n,则说明这两项间没有其他项了,用第2、3项继续生成,实际操作中为节省内存,我就把第一项(头结点)存盘,第2、3项又变为前两项,以此类推,最终只剩一项,则完成。把最后一项也存盘,根据统计出的法雷序列的字节数来为farey分配内存(大于最大整数32627则作失败处理)。
因为题目中函数原型为void FareySequence(int n, char farey[]);,只能对farey[]赋值但不能给它分配内存,也就是farey[]应在调用函数前分配内存,可是n不同时其占用的字节数变化很大,又无法用n估算其会占多少内存,所以我是在函数中求出法雷序列大小来后再分配内存的,为了这样,我把函数原型改成了
void FareySequence(int n, char **farey); ,不妥之处,请多多原谅。
我是在WinXP,Dev-C++下编译通过的,当n较大时执行时间会很长,我最大输入10000试了试,几分钟后才搞定,统计出分数个数为30397487个,保存序列的文件280多MB...
说了一大堆废话了,下面是我的程序:
#include <stdio.h>
#include <stdlib.h>
#define fenshu struct fs
#define MINN 1 /* n的最小值 */
#define MAXN 10000 /* n的最大值 */
fenshu /*表示分数的结构体 */
{int fenzi,fenmu; /*fenzi--分子 ,fenmu--分母*/
fenshu *next;
};
void huajian(int *fz,int *fm); /*将分数化为最简分数,fz为分子,fm为分母 */
void addnode(int nodesize,fenshu **place,int fz,int fm,long *nodenum); /*在指定位置后添加一个结点 */
void puthead(fenshu **head,FILE *fp, long *len); /*将头结点写入文件以释放内存空间 */
void FareySequence(int n, char **farey); /*产生法雷序列 */
int main()
{int n;
char *farey;
printf("Pleas input n:");
scanf("%d",&n);
if (!(n >= MINN && n <= MAXN))
{printf("Input error!\n"); system("pause"); exit(1);}
FareySequence(n,&farey);
if (farey!=NULL)
printf("F%d=\"%s\"\n",n,farey);
system("pause");
return 0;
}
void huajian(int *fz,int *fm) /*将分数化为最简分数,fz为分子,fm为分母 */
{int i,j,r;
i=*fm; j=*fz;
r=i%j;
while (r!=0)
{i=j; j=r; r=i%j; }
*fm/=j; *fz/=j;
}
void addnode(int nodesize,fenshu **place,int fz,int fm,long *nodenum) /*在指定位置后添加一个结点 */
{fenshu *p;
p=(fenshu *)malloc(nodesize);
p->fenzi=fz; p->fenmu=fm; p->next=(*place)->next;
(*place)->next=p;
(*nodenum)++;
}
void puthead(fenshu **head,FILE *fp, long *len) /*将头结点写入文件以释放内存空间 */
{fenshu *p;
p=*head; /* 保存原来结点 */
*len+=fprintf(fp,"%d/%d,",p->fenzi,p->fenmu); /* 写盘 */
*head=p->next; /*头结点后移 */
free(p); /* 释放原来结点 */
}
void FareySequence(int n, char **farey) /*产生法雷序列 */
{fenshu *head,*p;
int i,nodesize,fz,fm;
long len=0L,nodenum;
FILE *fp;
if((fp=fopen("farey.txt","w"))==NULL)
{printf("file can't open.\n"); exit(1); }
nodesize=sizeof(fenshu);
p=(fenshu *)malloc(nodesize); /*建立第一个结点 0/1 */
p->fenzi=0; p->fenmu=1; p->next=NULL;
head=p; nodenum=1L;
addnode(nodesize,&head,1,1,&nodenum); /*在链表后加上1/1,第二个结点*/
p=head->next; /*控制head,p始终指向链表最开始2个结点 */
/* 初始化完成,准备通过法雷序列的性质往链表中添加结点 */
while (NULL != p) /* p为空时head已是最后一个结点,添加结束 */
{fz=head->fenzi + p->fenzi;
fm=head->fenmu + p->fenmu;
huajian(&fz,&fm);
if (fm > n) /*计算出的分母大于n说明head,p间已不存在n级法雷序列的分数*/
puthead(&head,fp,&len); /*将头结点写入文件以释放内存空间 */
else /*否则将该分数添加到head与p之间*/
addnode(nodesize,&head,fz,fm,&nodenum);
p=head->next; /*较对p的位置*/
}
len+=fprintf(fp,"%d/%d",head->fenzi,head->fenmu); /*将最后一个结点写入文件 */
fclose(fp);
/*将法雷序列从文件读入farey中 */
printf("nodenum=%ld, len=%ld\n",nodenum,len);
if (len > 32626) /*若字节数超出整形范围(32626+'\0'即32627) */
{printf("string too long !"); goto fail; }
if (NULL==(*farey=(char *)malloc(len+1)))
{printf("momory not enough !"); goto fail; }
*(*farey+len)='\0';
if (NULL==(fp=fopen("farey.txt","rb")))
{printf("file can't open !"); goto fail; }
if (fread(*farey,1,len,fp)!=len)
{printf("file read error!"); goto fail; }
fclose(fp);
printf("Successful ! \n");
return;
fail:
*farey=NULL; printf("Failed !\nresult saved in\"farey.txt\".\n");
return;
}
我来回复