一元多项式计算器 (c语言数据结构实验)

班级 : ****
学号 : 201907020633
姓名 : ***
实验机号: A3
实验日期 :2020.12.04
报告日期 :2020.12.07

实验题目:一元多项式计算

一、概述

此次实验实现的功能有:
1.多项式加法
2.多项式减法(poly1-poly 2)
3.多项式乘法
4.多项式求值
5.多项式求导
6.多项式求不定积分
亮点:
对于运行中产生的数据文件如生成的多项式,运行结果,操作次数以及运行时间的存储,存储方式为仿系统日志文件的模式进行记录。方便对生成数据的分析以及对于错误数据的筛查和追溯。每次运行结果都会产生时间戳,保证数据的可靠性。

二、实验方案

1.设计方案

存储方案: 链式存储(方便插入和删除,顺序存储的插入和删除需要移动大量的数据,造成许多不必要的时间消耗)
实验逻辑:
在poly 1.txt和poly 2.txt文件中生成随机数。
当程序开始运行时数据被读入程序,同时被写入log.txt中作以记录。
继而进行下一步操作,如加减法、乘法、求值、求导、求不定积分。
执行完运算操作之后,将运算结果同时输出至屏幕和log.txt文件中。
如果需要继续执行,则将poly 1.txt和ploy 2.txt文件中的数据擦除,并重复上述操作。

2.函数调用关系

函数调用关系

3.关键算法实现
  1. 创建多项式文件
    思想:运用文件操作,生成随机数存储入poly 1.txt和poly 2.txt中。
    控制生成项数在指定范围内(即,rand()%11),尽量保持运算结果和生成数据方便分析,避免因为数据过大,无法及时发现计算中出现的错误。
void creat() 
{
     char s1[20]="poly 1.txt", s2[20]="poly 2.txt";
     srand((int)time(0));
     int n1 = rand()%10+1;
     FILE *fp1=fopen(s1,"w");
     for (int i=1;i<=n1;i++)
      {  if (i==1)
         fprintf(fp1,"%d", rand()%11);
         else fprintf(fp1," %d", rand()%11);
      }
       fclose (fp1);    
      int n2=rand()%10+1;
       FILE *fp2=fopen(s2,"w");
       for (int i=1;i<=n2;i++)
      {  if (i==1)
         fprintf(fp2,"%d", rand()%11);
         else  fprintf(fp2," %d", rand()%11);
      }   
     fclose (fp2);      
}
  1. 从文件中读入数据,生成多项式
    思想:运用feof,当文件中数据未被完全读入程序中时,保持运行。
    且如果指数相同时,系数相加。
PolyPtr getPoly (char *filename) 
{   
    PolyPtr poly=NULL,p;
    FILE *fp=fopen (filename,"r");
    if (!fp) return poly;
    poly= (PolyPtr)malloc(sizeof(Poly)) ;
    poly->coef=0;
    poly->expn=0;
    poly->next=NULL;
    while (!feof(fp))
      { 
        p= (PolyPtr)malloc(sizeof(Poly)) ;
        p->coef=0;
        p->expn=0;
        fscanf(fp,"%f %d",&p->coef,&p->expn);
        if (p->coef==0)
         {
            free(p);
            continue;
          }
                 
       PolyPtr  pre=poly;
       PolyPtr  q=poly->next;
        while (q&&q->expn<p->expn)
         {          
           pre=q;
           q=q->next;   
         }       
        if  (q&&q->expn==p->expn)
         {
            q->coef+=p->coef;
            free(p);
            continue;
         }
         p->next=q;
         pre->next=p;                     
      }
     return poly;
}
  1. 将运算结果和生成的多项式输出到屏幕上。
    思想:通过遍历输出多项式。
void PrintPoly(PolyPtr poly)  
{       
    PolyPtr p = poly->next; 
      if (!poly)
        return;
    while (p && p->coef == 0)
        p = p->next;
        FILE* file = fopen("log.txt", "a");
    if (!p)
    {
        printf("0");
        fprintf(file, "0\n");
        return;
    }
    if (p->expn != 0)
    {
        printf("%.2f x^%d", p->coef, p->expn);
        fprintf(file, "%.2f x^%d", p->coef, p->expn);
    }
    else {
        printf("%.2f", p->coef);
        fprintf(file, "%.2f", p->coef);
    }
    p = p->next;
    while (p)
    {
        if (p->coef != 0)
        {
            if (p->expn != 0)
            {
                if (p->coef > 0)
                {
                    printf("+ %.2f x^%d", p->coef, p->expn);
                    fprintf(file, "+ %.2f x^%d", p->coef, p->expn);
                }
                else {
                    printf(" %.2f x^%d", p->coef, p->expn);
                    fprintf(file, "% .2f x ^ %d", p->coef, p->expn);
                }
            }
            else
            {
                if (p->coef > 0)
                {
                    printf("+ %.2f", p->coef);
                    fprintf(file, "+ %.2f", p->coef);
                }
                else {
                    printf(" %.2f", p->coef);
                    fprintf(file, " %.2f", p->coef);
                }
            }
        }
        p = p->next;
    }
    fclose(file);
}
  1. 多项式加法
    思想
    (1)对于p1和p2初始化,然后指向Pa,Pb的首元;
    (2)p3指向Pc的当前结点,初值为Pa的头结点;
    (3)当指针p1和p2均未到达相应表尾时,则循环比较p1和p2所指结点对应的指数值:
    if:p1->expn == p2->expn,两个结点中系数相加,若不为零,则修改p1所指结点值,同时删除p2所指结点,若和为零,则删除p1和p2所指结点;
    elif:p1->expn < p2->expn,则应该摘取p1所指结点插入到和多项式链表中去; else:p1->expn >p2->expn,则应该摘取p2所指结点插入到和多项式链表中去;
    (4) 将非空多项式的剩余段插入到p3所指结点之后;
    (5)释放Pb的头结点;
    减法类似,将每项的系数置反,后续操作和加法相同。
PolyPtr Add(PolyPtr pa, PolyPtr pb)   
{
    PolyPtr p1=pa->next,p2=pb->next;
    PolyPtr p3=pa;
    PolyPtr r;
     while (p1&&p2)
       {
          
        if (p1->expn==p2->expn)
         {  cent++;
             float sum=p1->coef+p2->coef;
             if (sum!=0)
               {
                
                p1->coef=sum;
                p3->next=p1;
                p3=p1;
                r=p2;
                p2=p2->next;
                free(r);
                p1=p1->next;
               }
               
             else {
                    r=p2;
                    p2=p2->next;
                    free(r);
                     
                     r=p1;
                    p1=p1->next;
                    free(r); 
                
                 } 
             
            }       
        else if(p1->expn<p2->expn)
          {
            
            p3->next=p1;
            p3=p1;
            p1=p1->next;
         }
        
        else if(p1->expn>p2->expn)
          {
            
              p3->next=p2;
              p3=p2;
              p2=p2->next;
             }
        cent++;
       }
     p3->next=p1?p1:p2;
     cent++;
     free (pb);
     return pa;    
}
  1. 多项式乘法
    思想:借助辅助空链表L,利用poly1的指针所指的节点数值乘poly2每一项,将结果存储在链表L中。然后将指向该节点的指针后移到下一个节点重复上述操作;
PolyPtr Mult(PolyPtr pa, PolyPtr pb)  
{
    
    PolyPtr p1=pa->next, p2=pb->next;
    
    PolyPtr p3=(PolyPtr) malloc(sizeof(Poly));
    p3->next=0;
    PolyPtr head=p3;
    while (p1&&p2) 
    {
            cent++;
            PolyPtr pnew=(PolyPtr) malloc(sizeof(Poly));
            pnew->next=0;
            pnew->coef=p1->coef*p2->coef;
            pnew->expn=p1->expn+p2->expn;
            p3->next=pnew;
            p3=p3->next;
            p2=p2->next;
    }
    p1=p1->next;
    while (p1)
    {   
        PolyPtr p4=(PolyPtr) malloc(sizeof(Poly));
    p4->next=0;
    PolyPtr p5=p4;
        p2=pb->next;
        while (p2)
            {   cent++;
            PolyPtr pnew1=(PolyPtr) malloc(sizeof(Poly));
            pnew1->next=0;
            pnew1->coef=p1->coef*p2->coef;
            pnew1->expn=p1->expn+p2->expn;
            p4->next=pnew1;
            p4=p4->next;
            p2=p2->next;    
            }
        Add(head,p5);
    p1=p1->next;
    }
    return head ;
} 
  1. 多项式求值
    思想:遍历后逐项取值,后对所有值相加
float GetValue (PolyPtr p)
{    float x;
    printf ("设x的值为:");
    scanf ("%f",&x);
    FILE* fp0 = fopen("log.txt", "a");
    fprintf(fp0, "\nget valuex=%.2f\n", x);
    
    PolyPtr p1=p->next;
    float sum=0;
    while (p1)
    { cent++;
    sum+=p1->coef*pow(x,p1->expn);
    p1=p1->next;
    }
    printf ("多项式求值得到:%.2f\n",sum);
    fprintf(fp0,"sum = %.2f",sum);
    fclose(fp0);
    return sum;
}
  1. 多项式求导
    思想:通过遍历的方式,按照数学的规则进行运算。指数为零时,系数归零。其他的情况下,指数-1,对于系数*原指数。
PolyPtr  GetDerivation (PolyPtr p)
{
    PolyPtr head=p;
    PolyPtr p1=p->next;
    while (p1)
    {  cent++;
    if (p1->expn==0)
        p1->coef=0;
    else 
    {
        p1->coef=p1->coef*p1->expn;
        p1->expn-=1;
    }
    p1=p1->next;
    }
    return head;
} 
  1. 多项式求不定积分
    思想:通过遍历每一项,并对每项进行该操作后,指数+1,系数除以指数,按照正常的数学规则进行。
PolyPtr Getlntegration(PolyPtr p)   
{   PolyPtr head=p;
    PolyPtr p1=p->next;
    while (p1)
    {  cent++;
        if (p1->expn==0)
            p1->expn+=1;
        else{
            p1->coef=p1->coef/(1+p1->expn);
            p1->expn+=1;
            }   
    p1=p1->next;
    }
    return head;
}
  1. 销毁
    思想:通过遍历逐项释放空间
void Destroy (PolyPtr poly) 
{  PolyPtr p=poly->next;
    while (poly)
    {
        p=poly->next;
        free(poly);
        poly=p;
    }
}

三、实验过程

1.测试过程

测试数据:

1.00 x^1+ 3.00 x^6
Add result:1.00 x^1+ 3.00 x^6
|--->>> 2.59sec  1times     2020-12-6 23:21:48
9.00 x^4+ 3.00 x^6
18.00 x^1+ 5.00 x^9+ 7.00 x^10
Minus result:-18.00 x^1+ 9.00 x^4+ 3.00 x^6-5.00 x ^ 9-7.00 x ^ 10
|--->>> 6.29sec  7times     2020-12-6 23:21:51
7.00 x^6+ 4.00 x^7+ 2.00 x^8
8.00+ 5.00 x^1
Mult result:56.00 x^6+ 67.00 x^7+ 36.00 x^8+ 10.00 x^9
|--->>> 10.23sec  15times       2020-12-6 23:21:55
9.00 x^8+ 12.00 x^9+ 1.00 x^10
7.00+ 1.00 x^1+ 10.00 x^3+ 9.00 x^5
Minus result:-7.00-1.00 x ^ 1-10.00 x ^ 3-9.00 x ^ 5+ 9.00 x^8+ 12.00 x^9+ 1.00 x^10
|--->>> 12.41sec  9times        2020-12-6 23:21:57
5.00 x^4+ 2.00 x^10
11.00+ 2.00 x^1
Getvalue poly 1,poly 2 :
get valuex=1.00
sum = 7.00
get valuex=2.00
sum = 15.00
|--->>> 16.62sec  4times        2020-12-6 23:22: 2
3.00 x^6
6.00 x^1+ 5.00 x^3+ 4.00 x^4+ 9.00 x^6
GetDerivation result poly 1,poly 2:
18.00 x^5
6.00+ 15.00 x^2+ 16.00 x^3+ 54.00 x^5
|--->>> 19.54sec  5times        2020-12-6 23:22: 4
5.00 x^1+ 13.00 x^5+ 8.00 x^7+ 10.00 x^10
7.00+ 5.00 x^9
Minus result:-7.00+ 5.00 x^1+ 13.00 x^5+ 8.00 x^7-5.00 x ^ 9+ 10.00 x^10
|--->>> 24.39sec  8times        2020-12-6 23:22: 9
2.00+ 8.00 x^2+ 5.00 x^3
Add result:2.00+ 8.00 x^2+ 5.00 x^3
|--->>> 25.93sec  1times        2020-12-6 23:22:11
7.00 x^1+ 4.00 x^4+ 3.00 x^5+ 3.00 x^9+ 2.00 x^10
8.00+ 7.00 x^3+ 1.00 x^4+ 14.00 x^6
Mult result:56.00 x^1+ 81.00 x^4+ 31.00 x^5+ 126.00 x^7+ 25.00 x^8+ 27.00 x^9+ 72.00 x^10+ 42.00 x^11+ 21.00 x^12+ 17.00 x^13+ 2.00 x^14+ 42.00 x^15+ 28.00 x^16
|--->>> 28.02sec  62times       2020-12-6 23:22:13
8.00+ 7.00 x^9+ 7.00 x^10
1.00 x^1+ 7.00 x^2
Minus result:8.00-1.00 x ^ 1-7.00 x ^ 2+ 7.00 x^9+ 7.00 x^10
|--->>> 29.80sec  6times        2020-12-6 23:22:15
5.00+ 5.00 x^1+ 3.00 x^2+ 2.00 x^7+ 7.00 x^10
9.00+ 8.00 x^6+ 1.00 x^9+ 2.00 x^10
GetDerivation result poly 1,poly 2:
5.00+ 6.00 x^1+ 14.00 x^6+ 70.00 x^9
48.00 x^5+ 9.00 x^8+ 20.00 x^9
|--->>> 35.23sec  9times        2020-12-6 23:22:20
9.00 x^5
8.00+ 11.00 x^2+ 6.00 x^7+ 5.00 x^9
Getvalue poly 1,poly 2 :
get valuex=1.00
sum = 9.00
get valuex=2.00
sum = 3380.00
|--->>> 41.87sec  5times        2020-12-6 23:22:27
8.00 x^3
1.00 x^3+ 2.00 x^5+ 9.00 x^6
Getvalue poly 1,poly 2 :
get valuex=1.00
sum = 8.00
get valuex=2.00
sum = 648.00
|--->>> 54.27sec  4times        2020-12-6 23:22:39
10.00 x^2+ 10.00 x^8
7.00+ 3.00 x^1+ 10.00 x^7
GetDerivation result poly 1,poly 2:
20.00 x^1+ 80.00 x^7
3.00+ 70.00 x^6
|--->>> 62.43sec  5times        2020-12-6 23:22:47
9.00+ 4.00 x^2+ 3.00 x^6
3.00 x^5+ 6.00 x^10
Add result:9.00+ 4.00 x^2+ 3.00 x^5+ 3.00 x^6+ 6.00 x^10
|--->>> 64.50sec  5times        2020-12-6 23:22:49
9.00 x^1+ 12.00 x^5
2.00
Minus result:-2.00+ 9.00 x^1+ 12.00 x^5
|--->>> 68.19sec  3times        2020-12-6 23:22:53
2.调试分析

写出代码调试过程中遇到的问题及解决办法
主要遇到的问题: 文件指针加载项目相重叠,导致文件读写错误,文件多次重复打开;遇到未加载项。
问题界面
解决方案: 及时关闭文件,并对每个文件指针逐个命名,防止文件指针重复命名。

四、评价分析

1.实验结果分析

经过多次的修改,所的实验结果基本符合预期结果。
对于运行时间的计算相对于实际消耗时间有一定偏差。
原代码
printf(“运行时间:%.2lf秒\n”, (double)clock() / CLOCKS_PER_SEC);
改进解决方案:
clock_t start, finish;
double duration;
start = clock();
//操作
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf(“运行时间:%.2lf秒\n”,duration);
不同的运算操作产生的时间消耗不同,不同的数据规模所产生的时间消耗也有所不同。当问题规模较小时,乘法所花费的时间相对较少;当问题规模较大时,加减法所消耗的时间较少,数据量越大差异越明显。

2.算法性能评价

对实验的测量结果进行图示化呈现,分析算法性能,并给出优化方法

问题规模101001000100000
加法2.112.162.1510.36运行时间
乘法1.931.686.1135.420

问题规模与运行时间

优化方法:将乘法转换为加法,通过增加空间的方法换取时间性能上的提升。

五、总结与体会

通过本次实验加深了对于线性表的各项操作使用的印象,如线性表的遍历,线性表的插入删除,以及线性表的合并。
在仿日志的操作中也学会了生成时间戳的操作,如调用windows和time库。除此之外,对于文件各项操作也有了较为深入的了解。对于log.txt文件的探究过程中也对文件的读写存储过程有了较为深入的了解。
对于数据的分析过程中,由于对于excel表格相关的操作不太熟悉,导致制作的图表有很多的瑕疵,在以后的数据分析当中我会加强这方面的学习,毕竟excel等办公软件对于数据简单处理的过程,以及数据图示化有着极其重要的用途。
通过实验的调试,以及同学的帮助,这次实验中遇到的许多问题都得到了很好的解决。因此深深地体会到了知识是在探究中产生的,得到解决的。因此遇到问题不能只一个人在那冥思苦想,只有众人拾柴火焰高,才能获得更大的收获。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐