想要记录自己编程思维的成长所以发到博客,欢迎并且感激大家指出缺点和错误!
一、【实验构思(Conceive)】
本次实验要求是用C或C++语言设计并实现一个一元稀疏多项式的简单计算器,要求是要有如下功能
1、输入并建立多项式
2、输出多项式,序列按指数降序排列
3、多项式A(x)和B(x)相加,并建立多项式A(x)+B(x)
4、多项式A(x)和B(x)相减,并建立多项式A(x)-B(x)
5、给定 x 的值,计算多项式
6、多项式A(x)和B(x)相乘,建立多项式A(x)B(x) ( 选做,作为难度B的 操作)
二、【实验设计(Design)】
-
考虑一元多项式的数据结构(数据对象,数据关系,其上操作)如何表示与实现;
-
具体建立有头结点的一元多项式的结构实现用结构体实现,一个节点数据有两个,一个是double,一个是int,分别用来存储每一项的系数和指数,还有一个指针域的struct类型的指针next,指向下一个结点。
-
用createPolyn(Polyn, int)函数创建名为head的多项式,提示用户输入第一个多项式要输入几项,createPolyn()函数内调用insert()函数,插入输入的每一项,插入是即排序(序列按指数降序排列)
-
用printPolyn()函数实现打印,要分为多种情况:
1.系数大于0用‘+’连接,本身无符号,小于0的负数本身有符号‘-’,就不理会。
2.若系数为0,此项就为0
3.若系数不为0,
1)为1,不打印系数1:
指数为0,打印‘1’
指数为1,打印‘X’
2)为-1,不打印1,只打印‘-’
指数为0,打印‘-1’
指数为1,打印’-X’
3)其他数,打印‘系数X^指数 -
addPolyn()函数实现:用新链表hc来存结果,计算过程中,用cmp()函数比较两当前指针所指节点的指数大小,经过比较,决定是直接插入hc还是相加两节点系数值再判断是否为0后插入hc或者释放系数为0的节点,经过一次节点计算后,据情况指针后移。
-
subPolyb()函数即将第=减数多项式取反再调用addPolyn(),将取反后的多项式与原被减数多项式相加。
-
multiPolyn()函数实现:用新链表hc来存结果,计算过程中,第一个多项式的每一项都要去乘第二个多项式的所有项然后相加之和,有嵌套for循环实现,内层循环每次建立新hc节点来存储并插入结果。
-
derivation()求导函数实现,即将每一个指数不为0的项的系数指数重新赋值,系数=系数*指数 ,指数=指数- 1。
-
valueCount()函数的实现,输入X的值,再将其代入计算即得结果,同时计算输入的多项式a和b。
-
destroyPolyn()函数,每次结束一次操作就将多项式进行销毁,具体操作为节点存在即释放,销毁成功即返回OK,多项式不存在销毁失败,即返回FAILED。
-
cmp()函数用来比较两多项式中指针当前所指项系数大小.
三、【实现(Implement)】
抽象数据类型实现代码:
typedef struct lNode{
double coef;//多项式的系数
int expn;//多项式的指数
struct lNode *next;//指向下一个多项式的结点的指针
}*Polyn,Polynomial;
操作函数声明:
//操作函数声明
void Insert(Polyn, Polyn); //
Polyn createPolyn(Polyn,int);//建立一个头结点为head、项数为m的一元多项式
status destroyPolyn(Polyn);//销毁一元稀疏多项式链表,程序结束前应调用此函数释放多项式链表内存
void printPolyn(Polyn);//注意打印分类
//实现多项式的加减乘,求导
Polyn addPolyn(Polyn, Polyn);
Polyn subPolyn(Polyn, Polyn);
Polyn multiPolyn(Polyn, Polyn);
Polyn derivation(Polyn);
int cmp(Polyn, Polyn);
int valueCount(Polyn, int);
函数定义
status destroyPolyn(Polyn HEAD){//销毁存在的多项式链表
Polyn h, q = HEAD;
if(h == NULL)
return FAILED;
while(q){//循环销毁链表
Polyn p = q;
q = q -> next;
free(p);
}
return OK;
}
Polyn createPolyn(Polyn HEAD, int n){//输入m项的系数和指数,建立表示一元多项式的有序链表
int i;
Polyn p;
p = HEAD = (Polyn)malloc(sizeof(Polyn));
HEAD->next = NULL;
for(i = 0; i < n; i++)
{
p = (Polyn)malloc(sizeof(Polyn));//建立新结点以接收数据
printf("请输入第%d项的系数与指数(输入一个数就按回车):\n", i+1);
scanf("%lf %d", &p->coef, &p->expn);//注意double类型接收说明是%lf
Insert(p, HEAD); //调用Insert函数插入结点 将p节点插入链表HEAD中
}
return HEAD;
}
void Insert(Polyn p,Polyn HEAD){ //插入一项 就立刻排序 (插入算法)
if(p->coef == 0)
free(p);//系数为0的话没意义释放结点
else
{
Polyn q1,q2;
q1 = HEAD;//q1指向头结点
q2 = HEAD -> next;//q2指向第一个结点(也就是多项式第一项)
while(q2 && p->expn < q2->expn)//条件是q2指向的那一项 存在 且p输入的这一项的指数小于q2指向的那一项的指数(指数按从大到小排序)
{//查找插入位置
q1=q2;//q1指向下一项
q2=q2->next;//q2指向下一项
}
if(q2 && p->expn == q2->expn)
{//将指数相同相合并
q2->coef += p->coef;
free(p);//释放被合并的一项
if(!q2->coef) //若合并后原来的节点系数为O了也就释放原来的结点
{
q1->next = q2->next;
free(q2);
}
}
else
{//指数为新时将结点插入q1与q2之间
p->next = q2;
q1->next = p;
}
}
}
void printPolyn(Polyn HEAD){//在过程中使用,或者主函数调用
Polyn q;
q = HEAD->next;
int count;
count = 0;
if(!q){
printf("0\n");
return;
}
while(q){
if(q->coef > 0 && count != 0)//系数大于0的情况
printf("+");
if(q->coef != 1 && q->coef != -1){//系数不为正负一不需要特殊处理
printf("%.5f", q->coef);
if(q->expn == 1)
printf("X");
else if (q->expn)
printf("X^%d", q->expn);
}
else{
if(q->coef == 1){//系数为正负一需要特殊处理
if(!q->expn)
printf("1");
else if(q->expn == 1)
printf("X");
else
printf("X^%d", q->expn);
}
if(q->coef == -1){
if(!q->expn)
printf("-1");
else if(q->expn == 1)
printf("-X");
else
printf("-X^%d", q->expn);
}
}
q = q->next;
count++;
}
printf("\n");
}
int cmp(Polyn a, Polyn b){//计算过程中会用到的比较
if(a&&b){
if(!b || a->expn > b->expn) return 1;
else if(!a || a->expn < b->expn) return -1;
else return 0;
}
else if(!a && b)
return -1;//a多项式已空,但b多项式非空
else
return 1;//b多项式已空,但a多项式非空
}
Polyn addPolyn(Polyn ha, Polyn hb){
Polyn qa = ha->next;
Polyn qb = hb->next;
Polyn headc,hc,qc;
hc = (Polyn)malloc(sizeof(Polynomial));//建立头结点
hc->next = NULL;
headc = hc;
while(qa || qb)
{
qc = (Polyn)malloc(sizeof(Polynomial));
switch(cmp(qa,qb)){//比较qa和qb指针所指的两个节点
case 1://A的指数大于B的指数
{
qc->coef=qa->coef;//存qa
qc->expn=qa->expn;
qa=qa->next;//qa指针后移
break;
}
case 0://A的指数等于B的指数
{
qc->coef=qa->coef+qb->coef;//系数相加
qc->expn=qa->expn;//随便存个指数
qa=qa->next;//qa后移
qb=qb->next;//qb后移
break;
}
case -1://A的指数小于B的指数
{
qc->coef=qb->coef;//存qb
qc->expn=qb->expn;
qb=qb->next;//qb指针后移
break;
}
}
if(qc->coef!=0)//加法得到的新的QC结点系数不为0就将结点头插
{
qc->next=hc->next;
hc->next=qc;
hc=qc;
}
else free(qc);//当相加系数为0时,释放该结点
}
return headc;
}
Polyn subPolyn(Polyn ha, Polyn hb){
Polyn h = hb;
Polyn p = hb->next;
Polyn hd;
while(p)
{
p->coef *= -1;//将hb的系数取反,为了利用加法
p = p->next;
}
hd = addPolyn(ha, h);
for(p = h->next; p; p = p->next) //恢复hb的系数
p->coef *= -1;
return hd;
}
Polyn multiPolyn(Polyn ha, Polyn hb){//求解并建立多项式hf,返回其头指针
Polyn hf,pf;
Polyn qa = ha->next;
Polyn qb = hb->next;
hf = (Polyn)malloc(sizeof(Polynomial));//建立头结点
hf->next = NULL;
for(; qa; qa = qa->next)//嵌套循环,结果为qa的每一项要去乘qb的所有项的和
{
for(qb = hb->next; qb; qb = qb->next)
{
pf = (Polyn)malloc(sizeof(Polynomial));//建立新节点来插入hf
pf->coef = qa->coef * qb->coef;
pf->expn = qa->expn + qb->expn;
Insert(pf,hf);//调用Insert函数以插入并且合并指数相同的项
}
}
return hf;
}
Polyn derivation(Polyn HEAD){//求解并建立导函数多项式,并返回其头指针
Polyn q = HEAD->next;
Polyn p1, p2, hd;
hd = p1 = (Polyn)malloc(sizeof(Polynomial));//建立头结点
hd->next = NULL;
while(q){
if(q->expn != 0)//指数不为0时
{ //该项不是常数项时
p2 = (Polyn)malloc(sizeof(Polynomial));
p2->coef = q->coef*q->expn;//新的系数等于旧的系数和指数相乘
p2->expn = q->expn - 1;//新的指数等于旧的指数减一
p2->next = p1->next;//连接结点
p1->next = p2;
p1 = p2;
}
q = q->next;
}
return hd;
}
int valueCount(Polyn HEAD, int x){//求解指定X值的多项式的值
Polyn q, h;
q = h = HEAD;
q = h->next;
int result = 0;
while(q){
result += q->coef * pow(x, q->expn);
q = q->next;
}
return result;
}
四、【测试结果(Testing)】
五、【实验总结】
这次实验感觉比上一次对我的考验大,才发现很多程序我能看懂,但是当自己写就很难真的写出来,实际上机经验太少,是我的弱点。通过本次实验,我也对链表的理解与使用更为深刻和熟悉了,比如说建立head为头结点的新链表,对有头结点的链表的操作,插入结点函数的实现,插入立即排序,以便计算和打印,四个计算中加法和乘法算有技巧,减法就是取反相加,求导就是代入公式,计算多项式的值也是,加法的指针使用最体现链表的操作,主函数也花了不少时间写合法性检查,和计算操作的循环,是结束本次操作,还是退出程序,在调试的过程中发现多处可添加合法性检查。比如项数要为整型大于等于1,指数和系数要分别为整型和双精度,操作序号为整型,若输入不合法就重新输入。
六、【项目完成度评价】
正确性:a:程序不含语法错误;b:程序对于几组输入数据能够得出满足规格说明要求的结果;c:程序对于精心选择的典型,苛刻而带有刁难性的几组输入数据能够得出满足规格说明要求的结果;(待完成)d:程序对于一切合法的输入数据都能产生满足规格说明要求的结果(不能完成)
可读性:在编码过程中,写了很多注释,并且编码排版风格也一致
健壮性:当输入非法数据时,算法也能适当做出反应或进行处理,而不会产生莫名其妙的输出结果(待完善)
效率与低存储量需求:因为算法本身不难所以效率较高
七、【源代码】
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#define OK 1
#define FAILED 0
typedef int status;
//定义多项式的项存储结构,每一个结点对应稀疏多项式中的一项
typedef struct lNode{
double coef;//多项式的系数
int expn;//多项式的指数
struct lNode *next;//指向下一个多项式的结点的指针
}*Polyn,Polynomial;
//操作函数声明
void Insert(Polyn, Polyn); //
Polyn createPolyn(Polyn,int);//建立一个头结点为head、项数为m的一元多项式
status destroyPolyn(Polyn);//销毁一元稀疏多项式链表,程序结束前应调用此函数释放多项式链表内存
void printPolyn(Polyn);//注意打印分类
//实现多项式的加减乘,求导
Polyn addPolyn(Polyn, Polyn);
Polyn subPolyn(Polyn, Polyn);
Polyn multiPolyn(Polyn, Polyn);
Polyn derivation(Polyn);
int cmp(Polyn, Polyn);
int valueCount(Polyn, int);
//主函数
int main(void){
int m, n, x, y;
int a;
int flag;
Polyn ha = 0,hb = 0, pc;
printf(" 欢迎使用多项式简单操作程序\n\n");
while(a != 0){
printf("请输入a的项数:");
y = scanf("%d",&m);
while(!y || m <= 0){//合法性检查
fflush(stdin);
printf("输入错误请重新输入\n");
printf("请输入a的项数:");
y = scanf("%d",&m);
}
ha=createPolyn(ha,m);//建立多项式a
printf("请输入b的项数:");
y = scanf("%d",&n);
while(!y || n <= 0){//合法性检查
fflush(stdin);
printf("输入错误请重新输入\n");
printf("请输入b的项数:");
y = scanf("%d",&n);
}
hb=createPolyn(hb,n);//建立多项式b
//输出菜单
printf(" **********************************************************************\n");
printf(" * 多项式操作程序 *\n");
printf(" * *\n");
printf(" * 1:输出多项式a 2:输出多项式b *\n");
printf(" * *\n");
printf(" * 3:输出a的导数 4:输出b的导数 *\n");
printf(" * *\n");
printf(" * 5:输出a+b 6:输出a-b *\n");
printf(" * *\n");
printf(" * 7:输出a*b 8:退出此次操作 *\n");
printf(" * *\n");
printf(" * 9:退出程序 10:输入未知数的值计算多项式的值*\n");
printf(" **********************************************************************\n");
a = 1;//好进行跳出循环的判断
while(a == 1){
y = scanf("%d",&flag);
while(!y){//合法性检查
fflush(stdin);
printf("输入错误请重新输入\n");
printf("请输入操作数:");
y = scanf("%d",&flag);
}
switch(flag)
{
case 1:
{
printf(" 多项式a=");
printPolyn(ha);
break;
}
case 2:
{
printf(" 多项式b=");
printPolyn(hb);
break;
}
case 3:
{
pc = derivation(ha);
printf(" 多项式a的导函数为:a'=");
printPolyn(pc);
break;
}
case 4:
{
pc = derivation(hb);
printf(" 多项式b的导函数为:b'=");
printPolyn(pc);
break;
}
case 5:
{
pc = addPolyn(ha,hb);
printf(" a+b=");
printPolyn(pc);
break;
}
case 6:
{
pc = subPolyn(ha,hb);
printf(" a-b=");
printPolyn(pc);
break;
}
case 7:
{
pc = multiPolyn(ha, hb);
printf(" a*b=");
printPolyn(pc);
break;
}
case 8:
{
printf(" 此次操作结束!请重新输入多项式\n");
destroyPolyn(ha);
destroyPolyn(hb);
a = -1;
break;
}
case 9:
{
int l = destroyPolyn(ha);
int k = destroyPolyn(hb);
if(l == 1 && k == 1)
printf("销毁成功\n");
else
printf("销毁失败\n");
printf("即将退出\n");
return 0;
}
case 10:
{
int x, y;
printf("请输入未知数X的值\n");
y = scanf("%d", &x );
while(!y){
fflush(stdin);
printf("输入有误请重新输入\n");
y = scanf("%d", &x );
}
printf("多项式a的值为%d\n", valueCount(ha, x));
printf("多项式b的值为%d\n", valueCount(hb, x));
break;
}
default:
printf(" 您的选择错误,请重新选择操作数!\n");
}
}
}
return 0;
}
//函数定义
status destroyPolyn(Polyn HEAD){//销毁存在的多项式链表
Polyn h, q = HEAD;
if(h == NULL)
return FAILED;
while(q){//循环销毁链表
Polyn p = q;
q = q -> next;
free(p);
}
return OK;
}
Polyn createPolyn(Polyn HEAD, int n){//输入m项的系数和指数,建立表示一元多项式的有序链表
int i;
Polyn p;
p = HEAD = (Polyn)malloc(sizeof(Polyn));
HEAD->next = NULL;
for(i = 0; i < n; i++)
{
p = (Polyn)malloc(sizeof(Polyn));//建立新结点以接收数据
printf("请输入第%d项的系数与指数(输入一个数就按回车):\n", i+1);
scanf("%lf %d", &p->coef, &p->expn);//注意double类型接收说明是%lf
Insert(p, HEAD); //调用Insert函数插入结点 将p节点插入链表HEAD中
}
return HEAD;
}
void Insert(Polyn p,Polyn HEAD){ //插入一项 就立刻排序 (插入算法)
if(p->coef == 0)
free(p);//系数为0的话没意义释放结点
else
{
Polyn q1,q2;
q1 = HEAD;//q1指向头结点
q2 = HEAD -> next;//q2指向第一个结点(也就是多项式第一项)
while(q2 && p->expn < q2->expn)//条件是q2指向的那一项 存在 且p输入的这一项的指数小于q2指向的那一项的指数(指数按从大到小排序)
{//查找插入位置
q1=q2;//q1指向下一项
q2=q2->next;//q2指向下一项
}
if(q2 && p->expn == q2->expn)
{//将指数相同相合并
q2->coef += p->coef;
free(p);//释放被合并的一项
if(!q2->coef) //若合并后原来的节点系数为O了也就释放原来的结点
{
q1->next = q2->next;
free(q2);
}
}
else
{//指数为新时将结点插入q1与q2之间
p->next = q2;
q1->next = p;
}
}
}
void printPolyn(Polyn HEAD){//在过程中使用,或者主函数调用
Polyn q;
q = HEAD->next;
int count;
count = 0;
if(!q){
printf("0\n");
return;
}
while(q){
if(q->coef > 0 && count != 0)//系数大于0的情况
printf("+");
if(q->coef != 1 && q->coef != -1){//系数不为正负一不需要特殊处理
printf("%.5f", q->coef);
if(q->expn == 1)
printf("X");
else if (q->expn)
printf("X^%d", q->expn);
}
else{
if(q->coef == 1){//系数为正负一需要特殊处理
if(!q->expn)
printf("1");
else if(q->expn == 1)
printf("X");
else
printf("X^%d", q->expn);
}
if(q->coef == -1){
if(!q->expn)
printf("-1");
else if(q->expn == 1)
printf("-X");
else
printf("-X^%d", q->expn);
}
}
q = q->next;
count++;
}
printf("\n");
}
int cmp(Polyn a, Polyn b){//计算过程中会用到的比较
if(a&&b){
if(!b || a->expn > b->expn) return 1;
else if(!a || a->expn < b->expn) return -1;
else return 0;
}
else if(!a && b)
return -1;//a多项式已空,但b多项式非空
else
return 1;//b多项式已空,但a多项式非空
}
Polyn addPolyn(Polyn ha, Polyn hb){
Polyn qa = ha->next;
Polyn qb = hb->next;
Polyn headc,hc,qc;
hc = (Polyn)malloc(sizeof(Polynomial));//建立头结点
hc->next = NULL;
headc = hc;
while(qa || qb)
{
qc = (Polyn)malloc(sizeof(Polynomial));
switch(cmp(qa,qb)){//比较qa和qb指针所指的两个节点
case 1://A的指数大于B的指数
{
qc->coef=qa->coef;//存qa
qc->expn=qa->expn;
qa=qa->next;//qa指针后移
break;
}
case 0://A的指数等于B的指数
{
qc->coef=qa->coef+qb->coef;//系数相加
qc->expn=qa->expn;//随便存个指数
qa=qa->next;//qa后移
qb=qb->next;//qb后移
break;
}
case -1://A的指数小于B的指数
{
qc->coef=qb->coef;//存qb
qc->expn=qb->expn;
qb=qb->next;//qb指针后移
break;
}
}
if(qc->coef!=0)//加法得到的新的QC结点系数不为0就将结点头插
{
qc->next=hc->next;
hc->next=qc;
hc=qc;
}
else free(qc);//当相加系数为0时,释放该结点
}
return headc;
}
Polyn subPolyn(Polyn ha, Polyn hb){
Polyn h = hb;
Polyn p = hb->next;
Polyn hd;
while(p)
{
p->coef *= -1;//将hb的系数取反,为了利用加法
p = p->next;
}
hd = addPolyn(ha, h);
for(p = h->next; p; p = p->next) //恢复hb的系数
p->coef *= -1;
return hd;
}
Polyn multiPolyn(Polyn ha, Polyn hb){//求解并建立多项式hf,返回其头指针
Polyn hf,pf;
Polyn qa = ha->next;
Polyn qb = hb->next;
hf = (Polyn)malloc(sizeof(Polynomial));//建立头结点
hf->next = NULL;
for(; qa; qa = qa->next)//嵌套循环,结果为qa的每一项要去乘qb的所有项的和
{
for(qb = hb->next; qb; qb = qb->next)
{
pf = (Polyn)malloc(sizeof(Polynomial));//建立新节点来插入hf
pf->coef = qa->coef * qb->coef;
pf->expn = qa->expn + qb->expn;
Insert(pf,hf);//调用Insert函数以插入并且合并指数相同的项
}
}
return hf;
}
Polyn derivation(Polyn HEAD){//求解并建立导函数多项式,并返回其头指针
Polyn q = HEAD->next;
Polyn p1, p2, hd;
hd = p1 = (Polyn)malloc(sizeof(Polynomial));//建立头结点
hd->next = NULL;
while(q){
if(q->expn != 0)//指数不为0时
{ //该项不是常数项时
p2 = (Polyn)malloc(sizeof(Polynomial));
p2->coef = q->coef*q->expn;//新的系数等于旧的系数和指数相乘
p2->expn = q->expn - 1;//新的指数等于旧的指数减一
p2->next = p1->next;//连接结点
p1->next = p2;
p1 = p2;
}
q = q->next;
}
return hd;
}
int valueCount(Polyn HEAD, int x){//求解指定X值的多项式的值
Polyn q, h;
q = h = HEAD;
q = h->next;
int result = 0;
while(q){
result += q->coef * pow(x, q->expn);
q = q->next;
}
return result;
}