数据结构与算法lab1-哈工大
title: 数据结构lab1-一元多项式的代数运算
date: 2023-05-16 11:42:26
tags: 数据结构与算法
git地址:https://github.com/944613709/HIT-Data-Structures-and-Algorithms
哈尔滨工业大学计算机科学与技术学院
实验报告
课程名称:数据结构与算法
课程类型:必修
实验项目:线性表的链式存储结构与应用
实验题目:一元多项式的代数运算
实验日期:2021.10.13
班级:2003001
学号:120L021011
姓名:石卓凡
一、实验目的
1. 掌握线性表顺序存储结构的特点及线性表在顺序存储结构中各种基本操作的实现。
2. 掌握线性表链式存储结构的特点及线性表在链式存储结构中各种基本操作的实现。
3.重点巩固和体会线性表在链式存储结构上的各种操作和应用。
二、实验要求及实验环境
实验要求:
设计线性表的(动态或静态)链式存储结构,并实现一元多项式的代数运算。
以链表存储一元多项式,在此基础上完成对多项式的代数操作。
1.能够输入多项式(可以按各项的任意输入顺序,建立按指数降幂排列的多项式)和输出多项式(按指数降幂排列),以文件形式输入和输出,并显示。
2.能够计算多项式在某一点x=x0的值,其中x0是一个浮点型常量,返回结果为浮点数。
3.能够给出计算两个多项式加法、减法、乘法和除法运算的结果多项式,除法运算的结果包括商多项式和余数多项式。
4.要求尽量减少乘法和除法运算中间结果的空间占用和结点频繁的分配与回收操作。(提示:利用循环链表结构或可用空间表的思想,把循环链表表示的多项式返还给系统或可用空间表,从而解决上述问题)。
实验环境:
操作系统:Win7/Win10
集成开发环境:devcpp++
外部库:暂无
三、设计思想(本程序中的用到的所有数据类型的定义,主程序的流程图及各程序模块之间的调用关系)
1. 函数功能和外部接口设计
本系统总计设计了9个函数,每个函数的功能和接口设计如下表所示:
序号 | 函数名 | 函数功能 | 函数参数 | 函数返回值 |
---|---|---|---|---|
1 | Main | 根据order执行各函数 | 无 | 无 |
2 | ReadPoly | 读入In1.txt或者In2.txt里的多项式,并以降幂顺序存储进链表 | FILE *ff | Polynomial |
3 | Attach | 将链表尾插一个新节点,赋值coef和expon | float c, int e, Polynomial* pRear | NULL |
4 | Add | 加法,将结果存储至链表,返回表头 | Polynomial P1, Polynomial P2 | Polynomial |
5 | Sub | 减法,将结果存储至链表,返回表头 | Polynomial P1, Polynomial P2 | Polynomial |
6 | Mult | 乘法,将结果存储至链表,返回表头 | Polynomial P1, Polynomial P2 | Polynomial |
7 | Divide | 除法,直接打印和输出结果 | Polynomial P1, Polynomial P2 | NULL |
8 | PrintPoly | 根据链表表头将数据打印屏幕和输出到文件Out.txt | Polynomial P | NULL |
9 | Calulate | 计算Xo的结果,直接打印和输出结果 | Polynomial P,float x | NULL |
2. 主程序的流程图及各程序模块之间的调用关系
*流程图及程序模块的调用关系*
*各函数详细调用关系*
3. 数据类型的定义
typedef struct PolyNode *Polynomial;
struct PolyNode
{
**float coef; //**系数
**int expon; //**指数
Polynomial link;
}PolyNode;
**(一)**逻辑设计
(1) Attach插入项进入当前链表
\1. 新建结点t,将各个数值赋值
\2. 尾插法进入链表
(2) 从文件读入多项式
\1. 打开文件
\2. 创建链表的头结点
\3. 循环依次创建新节点,读入每一项的系数和指数,并且为尾插法Attach插入链表
\4. 删除空白头节点
(3) 加法
\1. 新建立链表头节点,和尾指针
\2. While循环,直到P1或者P2某个为空
2.1对于二者之间,拥有系数大的P,将P结点利用Attach(P1->coef,P1->expon,&Rear);插入链表
2.2对于二者之间,相同系数时候
2.2.1如果P1与P2当前系数和为0,则不用插入链表
2.2.2如果P1与P2当前系数和不为0,则插入链表Attach(P1->coef + P2->coef,P2->expon,&Rear);
3.while直到P1为空,不断Attach(P1->coef,P1->expon,&Rear);
4.While直到P2为空不断Attach(P2->coef,P2->expon,&Rear);
5.删除空白头节点
(4) 减法
\1. 新建链表头节点,和尾指针
\2. While循环直到P1或者P2某个为空
2.1对于二者之间,拥有系数大的P,将P结点利用Attach(P1->coef,P1->expon,&Rear);插入链表
2.2对于二者之间,相同系数时候
2.2.1如果P1与P2当前系数差为0,则不用插入链表
2.2.2如果P1与P2当前系数差不为0,则进行插入,Attach((P1->coef)-(P2->coef),P1->expon,&Rear);
\3. While直到P1为空Attach(P1->coef,P1->expon,&Rear)
\4. While直到P2为空Attach(-(P2->coef),P2->expon,&Rear);
\5. 删除空白头节点
(5) 乘法
\1. 如果P1或者P2为空则返回NULL,t1=P1,t2=P2
\2. 新建链表头节点=P
\3. While直到t1为空
(1) 赋值t2=P2,Rear=P
(2) While直到t2为空
① 计算当前t1和t2项乘法之后的系数和指数
② While循环去找到需要当前乘法结果需要插入的位置
③ 情况1在链表尾部插入,情况2在链表中间插入(Rear->link==NULL||Rear->link->expon < e)
④ 情况3(Rear->link->expon == e)当前可以进行合并
\1) 如果合并后是0则不需要插入,并且进行删除对应位置的节点
\2) 如果合并后不是0则进行插入
(6) 除法
a. 判断除数P2是否为0,如果是0则无法进行除法
b. 新建链表头节点,t1=P1,t2=P2
c. While一直循环
a) 计算当前商的项的指数newe和系数newc
b) 如果(P2->expon==0)当除数是常数(x是0次方)只需要出一次就能够得到,且余数多项式一定为0 。直接将Attach(newc,newe,&RearS);将商项插如商多项式。根据短除法,将Ptemp1 = Mult(RearS,P2),Ptemp1 = Sub(t1,Ptemp1);t1=Ptemp1;并且结束循环break
c) 如果t1->expon < P2->expon已经达到了结束循环条件进行break
d) 否则,直接计算将Attach(newc,newe,&RearS);将商项插如商多项式。根据短除法,将Ptemp1 = Mult(RearS,P2),Ptemp1 = Sub(t1,Ptemp1);t1=Ptemp1
(7) 计算x0
a. While循环
a) sum+=(P->coef)*pow(x,P->expon);
b) P=P->link;
**(二)**物理设计
表达式用链表存储,链表的结点就是表达式中的每一项用PolyNode表示,coef为系数,expon为指数,link指向下一项
struct PolyNode
{
float coef;
int expon;
Polynomial link;
}PolyNode;
**四、**测试结果
测试用例1:
F1 = 1x2-3x1+1x^0
F2 = 3x3-5x1+6x^0
测试样例2
F1=9x2+0x5-2x^2
F2=0x0+1x1
**五、**经验体会与不足
不足:
1. 对于加减乘除后出现的系数为0的数据(比如0x^4),前期没有考虑到究竟选择删除该节点还是保留,导致后期混乱没有统一
解决方法:统一为系数为0的数据删除节点,在ReadPoly中再进行补充条件防止输出为空
2. 对于最初尝试除法的函数时候,空间的占用和结点的删除过于频繁
解决方法:将原本定义了多个的Polynomial可以合并通用的都合并了,减少了相当一部分的多余使用
经验体会:
a. 对于一个程序需要多个测试样例来找出程序所存在的BUG和当前没有考虑到的情况,比如此程序中的极端情况,除数多项式为0时候不存在,比如最后输出0x^0时候的符号判定是个特殊情况
b. 链表中空间的占用和结点的释放需要多加注意,有很多重复使用的可以删掉,系数为0的也可以不用浪费结点
c. 对于尾插法和在中间插入一个节点,所使用到的代码都是通用的,可以将两块情况合并在一起。
六、附录:源代码(带注释)
\#include<stdio.h>\#include<stdlib.h>\#include<math.h>typedef struct PolyNode *Polynomial;struct PolyNode{float coef;int expon;Polynomial link;}PolyNode;Polynomial ReadPoly(FILE *ff);void Attach(float c, int e, Polynomial* pRear);Polynomial Add(Polynomial P1, Polynomial P2);Polynomial Sub(Polynomial P1, Polynomial P2);Polynomial Mult(Polynomial P1, Polynomial P2);void PrintPoly(Polynomial P);void Calulate(Polynomial P,float x);void Divide(Polynomial P1, Polynomial P2);void Sort(Polynomial P);int main(){ Polynomial P1,P2,P; FILE *fp1=NULL; FILE *fp2=NULL; fp1= fopen("In1.txt","r"); fp2= fopen("In2.txt","r"); printf(" -------------------------------------------------------------------\n");printf(" |================== 一元多项式的运算 =================|\n");printf(" -------------------------------------------------------------------\n\n");printf(" |================== 1.相加(+) =================|\n");printf(" |================== 2.相减(-) =================|\n");printf(" |================== 3.相乘(*) =================|\n");printf(" |================== 4.相除(/) =================|\n");printf(" |================== 5.计算Xo(=) =================|\n");int n;printf("请输入选择:");scanf("%d",&n);switch (n){case 3: P1 = ReadPoly(fp1); P2 = ReadPoly(fp2); P=Mult(P1,P2); printf("f1*f2="); PrintPoly(P); break; case 1: P1 = ReadPoly(fp1); P2 = ReadPoly(fp2); P=Add(P1,P2); printf("f1+f2="); PrintPoly(P); break; case 4: P1 = ReadPoly(fp1); P2 = ReadPoly(fp2); Divide(P1,P2);//除法 break; case 2: P1 = ReadPoly(fp1); P2 = ReadPoly(fp2); P=Sub(P1,P2); printf("f1-f2="); PrintPoly(P); break; case 5: float x; printf("请输入xo:"); scanf("%f",&x); P1 = ReadPoly(fp1); P2 = ReadPoly(fp2); printf("f1(xo)="); Calulate(P1,x); printf("f2(xo)="); Calulate(P2,x); } fclose(fp1); fclose(fp2);}void PrintPoly(Polynomial P){ FILE *p; if((p=fopen("Out.txt","a"))==NULL) { printf("文件打开失败"); exit(0); } fprintf(p,"当前结果为:"); int flag = 0; // 判断是否是开头int Emptyflag = 1 ;//标记是否最终结果是否一个没输出,如果是1->Empty则输出0x^0 if (!P){ printf("NULL");//当结果是NULL,P就是NULL,用以观测是否会出现P==NULL fprintf(p,"NULL"); return;}while (P){ if(P->coef==0) //对于0x^2直接跳过不输出 { P = P->link; continue; } if(P->coef>0&&flag==1)//flag==1 不是开头则就要考虑+符号 { printf("+"); fprintf(p,"+"); } printf("%.2fx^%d ", (P->coef), P->expon); fprintf(p,"%.2fx^%d ", (P->coef), P->expon); Emptyflag=0;//输出有非0数据 P = P->link; if(flag==0) flag=1;}if(Emptyflag==1)//如果P结果全是 0x^2+0x^1则只输出为0x^0 { printf("0.00x^0");//结果为0总得输出一个 fprintf(p,"0.00x^0"); }printf("\n");fprintf(p,"\n");fclose(p);}Polynomial Mult(Polynomial P1, Polynomial P2){ Polynomial P,t1,t2,t,Rear; if(!P1||!P2) return NULL;//防止P1或P2万一为NULL,报错提示 t1=P1; t2=P2; float c; int e; P=(Polynomial)malloc(sizeof(PolyNode)); P->link=NULL; while(t1)//固定P1中的某个,依次遍历P2每一个 { t2=P2; Rear=P; while(t2)//t2==NULL 停下 { c=t1->coef * t2->coef; e=t1->expon + t2->expon; while(Rear->link!=NULL&&Rear->link->expon > e)//利用降幂顺序 来while循环找到插入的对应位置 Rear=Rear->link; if(Rear->link==NULL||Rear->link->expon < e)//在结尾插入(Rear->link==NULL) 和 在中间插入,都可以归为插入 { //(Rear->link->expon)在中间插入 t=(Polynomial)malloc(sizeof(PolyNode)); t->coef=c; t->expon=e; t->link=Rear->link; Rear->link=t; } else if(Rear->link->expon == e)//发现插入的可以合并同类项 { if(c + Rear->link->coef !=0)//合并之后不是0 { Rear->link->coef += c; } else if (c + Rear->link->coef ==0)//合并之后为0直接删除结点 { Polynomial temp; temp=Rear->link; Rear->link=Rear->link->link; free(temp); } } t2=t2->link; } t1=t1->link; } t=P; P=P->link; free(t); return P;}Polynomial Add(Polynomial P1, Polynomial P2){ Polynomial P,Rear,t; P=(Polynomial)malloc(sizeof(PolyNode)); P->link=NULL; Rear=P; while(P1&&P2)//从两个多项式依照降幂顺序,找指数高的开始 { if((P1->expon) > (P2->expon) ) { Attach(P1->coef,P1->expon,&Rear); P1=P1->link; } else if ((P1->expon) < (P2->expon)) { Attach(P2->coef,P2->expon,&Rear); P2=P2->link; } else { if(P1->coef + P2->coef!=0) { Attach(P1->coef + P2->coef,P2->expon,&Rear); P1=P1->link; P2=P2->link; } else//coef = = 0 { P1=P1->link; P2=P2->link; }//一旦系数为0都不存入结点 } } while(P1) {Attach(P1->coef,P1->expon,&Rear); P1=P1->link; } while(P2) {Attach(P2->coef,P2->expon,&Rear); P2=P2->link; } t=P; P=P->link; free(t); if(!P) { P=(Polynomial)malloc(sizeof(PolyNode)); P->link=NULL; P->coef =0; P->expon =0; }//当结果为0时候防止P==NULL,不妨将新建结点,数据为0x^0 return P;}Polynomial Sub(Polynomial P1, Polynomial P2) //P1-P2 { Polynomial P,Rear,t; P=(Polynomial)malloc(sizeof(PolyNode)); P->link=NULL; Rear=P; while(P1&&P2) { if((P1->expon) > (P2->expon) )//按照降幂这么放入P { Attach(P1->coef,P1->expon,&Rear); P1=P1->link; } else if ((P1->expon) < (P2->expon)) { Attach(-(P2->coef),P2->expon,&Rear); P2=P2->link; } else if ((P1->expon) == (P2->expon)) { if((P1->coef) -(P2->coef) == 0) { P1=P1->link; P2=P2->link; } else { Attach((P1->coef)-(P2->coef),P1->expon,&Rear); P1=P1->link; P2=P2->link; } } } while(P1) {Attach(P1->coef,P1->expon,&Rear); P1=P1->link; } while(P2) {Attach(-(P2->coef),P2->expon,&Rear); P2=P2->link; } t=P; P=P->link; free(t); if(!P) { P=(Polynomial)malloc(sizeof(PolyNode)); P->link=NULL; P->coef =0; P->expon =0; }//当结果为0时候防止P==NULL,不妨将新建结点,数据为0 return P;}void Attach(float c, int e, Polynomial* pRear){ Polynomial t; t=(Polynomial)malloc(sizeof(PolyNode)); t->coef=c; t->expon=e; t->link=NULL; (*pRear)->link=t;//利用尾插法,当然要将尾结点指向更新,*pRear才能修改尾结点自己地址 *pRear=t;}Polynomial ReadPoly(FILE *ff){ int exp; float coe; char ch; Polynomial P,Rear,t,Head; P=(Polynomial)malloc(sizeof(PolyNode)); P->link=NULL; Rear=P;ch = fgetc(ff);if(ch==EOF)//看txt文本是否为空 { printf("ERROR: In.txt输入为空"); exit(0); }if(ch!='-')//3x^2+3x^1这种首项第一个不会带有+,特殊情况 { rewind(ff); fscanf(ff,"%fx^%d",&coe,&exp); Attach(coe,exp,&Rear); } else//ch='-' { fscanf(ff,"%fx^%d",&coe,&exp); Attach((-coe),exp,&Rear); } while(fscanf(ff,"%c%fx^%d",&ch,&coe,&exp)!=EOF)//开始按照降幂插入 { if(ch=='-')//如果是符号要调整coe coe=-coe; Head=P; while(Head->link!=NULL&&Head->link->expon > exp ) // Head=Head->link; if(Head->link==NULL||Head->link->expon < exp) { t=(Polynomial)malloc(sizeof(PolyNode)); t->coef=coe; t->expon=exp; t->link=Head->link; Head->link=t; } else if(Head->link->expon == exp) { if(coe + Head->link->coef !=0) { Head->link->coef += coe; } else if (coe + Head->link->coef ==0) { t=Head->link; Head->link=Head->link->link; free(t); }//对于0x^2这种数据直接删掉结点 } } t=P; P=P->link; free(t); printf("f(x)="); PrintPoly(P); return P;//若In.txt为空则输出0x^0 }void Calulate(Polynomial P,float x){ FILE *p; if((p=fopen("Out.txt","a"))==NULL) { printf("文件打开失败"); exit(0); } float sum; sum=0; while(P) { sum+=(P->coef)*pow(x,P->expon); P=P->link; } printf("%f",sum); fprintf(p,"代入Xo之后等于:%f",sum); fclose(p); printf("\n");}void Divide(Polynomial P1, Polynomial P2)//p1 / p2 { Polynomial PS,t1,t2,RearS,Ptemp1,t; PS=(Polynomial)malloc(sizeof(PolyNode));//商多项式 PS->link=NULL; RearS=PS;//用来存储 t1=P1; t2=P2; if(P2->coef==0&&P2->expon==0)//当除数时0,数学公式不成立 { printf("ERROR:P2不能为0"); exit(0); } float newc; int newe; while(1)//进入循环 { if(P2->expon==0)//特殊情况,当除数是常数(x是0次方)只需要出一次就能够得到,且余数多项式一定为0 { newe=t1->expon - P2->expon;//本次依次得到的商的一个项的指数 newc=t1->coef / P2->coef;//本次依次得到的商的一个项的系数 Attach(newc, newe, &RearS);//将当前项,加入到商多项式 Ptemp1 = Mult(RearS,P2);//PP1*P2 = Ptemp,除法公式用到的 Ptemp1 = Sub(t1,Ptemp1);//除法公式用到的 t1=Ptemp1;//再次进行,当前短除法之后得到的余数多项式(不一定是最终的余数),成为新的t1,继续试探 break; } if(t1->expon < P2->expon) { //已经完成商多项式 余数多项式 //t1就是最终余数多项式 break;//终止循环唯一条件 } else//需要继续除 { newe=t1->expon - P2->expon;//本次依次得到的商的一个项的指数 newc=t1->coef / P2->coef;//本次依次得到的商的一个项的系数 Attach(newc, newe, &RearS);//将当前项,加入到商多项式 Ptemp1 = Mult(RearS,P2);//PP1*P2 = Ptemp Ptemp1 = Sub(t1,Ptemp1); t1=Ptemp1;//再次进行,当前短除法之后得到的余数多项式(不一定是最终的余数),成为新的t1,继续试探 } } t=PS; PS=PS->link; free(t);//删掉PS空白头结点 if(!PS)//对于0/9x = 0 ..9x 此时防止商为空 { PS=(Polynomial)malloc(sizeof(PolyNode));//商多项式 PS->link=NULL; PS->coef = 0; PS->expon = 0; } printf("余数多项式:"); PrintPoly(t1);//开始输出余数多项式 printf("商多项式:"); PrintPoly(PS);//已经完成输出商多项式 }
数据结构与算法lab1-哈工大相关推荐
- 《数据结构与算法》三元组的基本操作
用c语言实现<数据结构与算法(严蔚敏版)>三元组的基本操作 (大二数据结构课的Lab1) 以下源代码(因为对指针不太清楚,所以用到了c++中的引用,而且这也是书中所给算法框架的做法) #i ...
- Python3-Cookbook总结 - 第一章:数据结构和算法
第一章:数据结构和算法 Python 提供了大量的内置数据结构,包括列表,集合以及字典.大多数情况下使用这些数据结构是很简单的. 但是,我们也会经常碰到到诸如查询,排序和过滤等等这些普遍存在的问题. ...
- 推荐一个关于.NET平台数据结构和算法的好项目
http://www.codeplex.com/NGenerics 这是一个类库,它提供了标准的.NET框架没有实现的通用的数据结构和算法.值得大家研究. 转载于:https://www.cnblog ...
- 数据结构和算法:(3)3.1线性表的顺序存储结构
-----------------------1.线性表基础操作------------------------ 线性表:(List)由零个或多个数据元素组成的有限序列. 首先他是一个序列,元素之间是 ...
- weiss数据结构和算法书的使用说明
<数据结构与算法分析 C语言描述>Mark Allen Weiss著,冯舜玺译,机械工业出版社.Weiss教授的经典教材三部曲之一,其中的C语言描述版本,也就是本书,被称为20世纪最重要的 ...
- 数据结构和算法 -- 学习导图
数据结构和算法 是作为程序员写出高效代码的基础,为了今后的两年在高效代码之路上持续精进,将按照此学习导图进行 算法和数据结构的刻意练习,同时也希望为同样有高效代码追求的伙伴们提供一条学习路径,共同进步 ...
- Java数据结构与算法(第四章栈和队列)
2019独角兽企业重金招聘Python工程师标准>>> 本章涉及的三种数据存储类型:栈.队列和优先级队列. 不同类型的结构 程序员的工具 数组是已经介绍过的数据存储结构,和其他结构( ...
- python数据结构与算法总结
python常用的数据结构与算法就分享到此处,本月涉及数据结构与算法的内容有如下文章: <数据结构和算法对python意味着什么?> <顺序表数据结构在python中的应用> ...
- 学习JavaScript数据结构与算法(一):栈与队列
本系列的第一篇文章: 学习JavaScript数据结构与算法(一),栈与队列 第二篇文章:学习JavaScript数据结构与算法(二):链表 第三篇文章:学习JavaScript数据结构与算法(三): ...
- MySQL索引背后的数据结构及算法原理【转】
http://blog.codinglabs.org/articles/theory-of-mysql-index.html MySQL索引背后的数据结构及算法原理[转] 摘要 本文以MySQL数据库 ...
最新文章
- 2022-2028年中国半导体用环氧塑封料(EMC)行业市场全景调查及投资前景分析报告
- Runnable和Thread的区别
- 国内敏捷项目协作工具亲测推荐
- tensorflow--模型的保存和提取
- Android(Fragment和Activity之间通信)
- 与敏捷团队一起交付价值
- python server酱_Python 超简单的邮件发送方法
- 《代码的未来》读书笔记:内存管理与GC那点事儿
- seaborn—sns.scatterplot绘制散点图
- QT5使用PCAN读取CAN数据
- 计算机音乐模式怎么设置,电脑开机时自启QQ音乐APP播放歌曲的功能在哪里设置...
- 新医药与生命健康专题讲座
- app推广渠道数据统计Xintall
- java实现随机游走算法_java – 简单的2D随机游走
- Python编程语言好学吗 怎么能学好Python开发
- CH579中ADC增益多通道自动换挡
- anacoda里面安装包显示失败_Premiere2020安装包下载及安装教程(附pr2020配置要求)...
- 讲真,这可能是博客图床最佳解决方案
- Non_Local_Means滤波器----MATLAB
- Collection类和泛型