一元稀疏多项式计算器
问题描述
设计一个一元稀疏多项式简单计算器。
基本要求
(1)输入并建立多项式。
(2)输出多项式,输出形式为整数序列:n,c1,e1,c2,e2,…,cn,en,其中n是多项式的项数,ci,ei分别是第i 项的系数和指数,序列按指数降序排列。
(3)实现多项式a和b相加,建立多项式a+b。
(4)实现多项式a和b相减,建立多项式a-b。
(5)计算多项式在x处的值。
(6)计算器的仿真界面。
测试数据
带界面版
博客地址: 一元稀疏多项式计算器仿真界面版
相关代码
不带界面,只包含数据结构的设计。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
typedef struct Polynomial //多项式
{
float coef; //系数
int expn; //指数
struct Polynomial *next;//指针
} Polynomial, *Polyn;
//创建一个头指针为head,项数为m的一元多项式
Polyn CreatPolyn(Polyn head, int m)
{
head = (Polyn)malloc(sizeof(struct Polynomial));
head->next = NULL;
for (int i = 1; i <= m; i++)
{
Polyn p = (Polyn)malloc(sizeof(struct Polynomial));
printf("请输入第%d项的系数与指数:", i);
scanf("%f%d", &p->coef, &p->expn);
if (p->coef == 0) free(p);
else
{
Polyn q1, q2;
q1 = head;
q2 = head->next;
while (q2 != NULL && p->expn < q2->expn)
{
q1 = q2;
q2 = q2->next;
}
if (q2 != NULL && p->expn == q2->expn)
{
q2->coef += p->coef;
if (q2->coef == 0)
{
q1->next = q2->next;
free(q2);
}
free(p);
}
else
{
p->next = q2;
q1->next = p;
}
}
}
return head;
}
void printPoLlyn(Polyn head)
{
Polyn q = head->next;
int flag = 0; //记录是否为第一项
if (!q)
{
puts("0");
puts("\n");
return;
}
while (q)
{
if (q->coef > 0 && flag == 1)
{
printf("+");
}
flag = 1;
if (q->coef != 1 && q->coef != -1)
{
printf("%g", q->coef);
if (q->expn == 1) printf("x");
else if (q->expn!=0) printf("x^%d", q->expn);
}
else
{
if (q->coef == 1)
{
if (q->expn == 0) printf("1");
else if (q->expn == 1) printf("x");
else printf("x^%d", q->expn);
}
if (q->coef == -1)
{
if (q->expn == 0) printf("-1");
else if (q->expn == 1) printf("-x");
else printf("-x^%d", q->expn);
}
}
q = q->next;
}
printf("\n");
}
int compare(Polyn a, Polyn b)//比较两个多项式的大小
{
if (a&&b) // 多项式a和b均不为空
{
if (a->expn > b->expn) return 1;// a的指数大于b的指数
else if (a->expn < b->expn) return -1;
else return 0;
}
else if (!a&&b) return -1; //a为空,b不为空
else if (a&&!b) return 1; //b为空,a不为空
else if (!a&&!b)return 0; //a,b均为空
}
Polyn addPolyn(Polyn a, Polyn b) //求解a+b,并返回头结点head
{
Polyn head ,qc;
Polyn qa = a->next;
Polyn qb = b->next;
Polyn hc=(Polyn)malloc(sizeof(Polynomial));
hc->next = NULL;
head = hc;
while (qa || qb)
{
qc= (Polyn)malloc(sizeof(Polynomial));
if (compare(qa, qb) == 1)
{
qc->coef = qa->coef;
qc->expn = qa->expn;
qa = qa->next;
}
else if (compare(qa, qb) == 0) //指数相同,直接相加
{
qc->coef = qa->coef + qb->coef;
qc->expn = qa->expn ;
qa = qa->next;
qb = qb->next;
}
else
{
qc->coef = qb->coef;
qc->expn = qb->expn;
qb = qb->next;
}
if (qc->coef != 0) //将该节点插入链表中
{
qc->next = hc->next;
hc->next = qc;
hc = qc;
}
else free(qc);
}
return head;
}
Polyn subPolyn(Polyn a, Polyn b)
{
Polyn h = b;
Polyn p = b->next;
while(p)
{
p->coef *= -1;
p = p->next;
}
Polyn head = addPolyn(a, h);
for (Polyn i = h->next; i != 0; i = i->next)
{
i->coef *= -1;
}
return head;
}
double value(Polyn head, int x) //计算x的值
{
double sum = 0;
for (Polyn p = head->next; p != 0; p = p->next)
{
int tmp = 1;
int expn = p->expn;
while(expn != 0) //指数不为0
{
if (expn < 0) tmp /= x, expn++;
else if(expn>0) tmp *= x, expn--;
}
sum += p->coef*tmp;
}
return sum;
}
int main()
{
int m;
Polyn a = 0, b = 0;
printf("请输入a的项数:");
scanf("%d", &m);
a = CreatPolyn(a, m);
printPoLlyn(a);
printf("请输入b的项数:");
scanf("%d", &m);
b = CreatPolyn(b, m);
printPoLlyn(b);
printf("输出 a+b:");
printPoLlyn(addPolyn(a, b));
printf("输出 a-b:");
printPoLlyn(subPolyn(a, b));
printf("请输入x的值:");
int x;
scanf("%d", &x);
printf("输出a的多项式的值为:%.2lf", value(a,x));
return 0;
}
/*
测试数据:
3
2 1
5 8
-3.1 11
3
7 0
-5 8
11 9
1
*/
设计详解
1、一元稀疏多项式的建立
结构体的定义
typedef struct Polynomial //多项式
{
float coef; //系数
int expn; //指数
struct Polynomial *next;//指针
} Polynomial, *Polyn;
使用带头结点的单链表存贮多项式,插入查找和删除较为方便。数据域中存贮系数和指数,指针域指向下一个节点的位置。
如果所示的存贮结构:
设计思想:
首先确定好多项式的项数m
,新建立一个节点p
,用来存贮读入的系数coef
和项数expn
。然后再定义两个指针q1
和q2
,一前一后,分别指向多项式的两个相邻节点。为了实现多项式的降序排列,这里我们利用插入排序的思想,如果p
和q2
的指数相同,即p->expn == q2->expn
,则进行两个节点的合并。如果p
的指数小于q2
的指数,即p->expn < q2->expn
,继续后移两个指针。否则,p
的指数小于q1
的指数,大于q2
的指数,我们找到了插入的位置,将p
节点插入两个节点中。执行m
次插入操作,就将一元稀疏多项式的建立好了。最后注意要将系数coef==0
的节点释放。
定义两个指针:
找到了插入位置,将节点p插入
代码
//创建一个头指针为head,项数为m的一元稀疏多项式
void CreatPolyn(Polyn head, int m)
{
for (int i = 1; i <= m; i++)
{
Polyn p = (Polyn)malloc(sizeof(struct Polynomial)); //新建节点p
printf("请输入第%d项的系数与指数:", i);
scanf("%f%d", &p->coef, &p->expn);
if (p->coef == 0) free(p); //将系数为0的节点释放
else
{
Polyn q1, q2; //两个指针一前一后
q1 = head;
q2 = head->next;
while (q2 != NULL && p->expn < q2->expn) //p的指数小于q2的指数
{
q1 = q2; //继续后移两个指针
q2 = q2->next;
}
if (q2 != NULL && p->expn == q2->expn) //将相同指数的项进行合并
{
q2->coef += p->coef; //合并两项
if (q2->coef == 0)
{
q1->next = q2->next;
free(q2); //将系数为0的节点释放
}
free(p); //将节点p释放
}
else
{
p->next = q2; //将节点p插入到q1和q2之间
q1->next = p;
}
}
}
}
2.一元稀疏多项式的加法和减法运算
设计思想:
关于多项式的加法运算。首先要定义一个比较函数compare
,来比较两个多项式的每项指数大小。
我们从头到尾处理两个多项式的每一项。如果两项中,多项式a
的项的指数大于多项式b
的项的指数,那么将a
的此项直接作为多项式c
的一项。如果多项式a
的指数等于多项式b
的指数,将两项合并作为多项式c
的一项。如果多项式a
的指数小于多项式b
的指数,那么将b
的此项直接作为多项式c
的一项。
因为多项式a
和多项b
的都是按照指数降序建立的,因此,指数大的项会被先计算出来,使用尾插法插入多项式c
中,这样多项式c
也是按照指数降序排列的。而减法就是将a-b
改为a+(-b)
。我们将b
的每一项系数都取相反数,最后按照加法计算。
图示过程:
c = a+b
将计算出来的qc
节点使用尾插法插入多项式c
中,然后再将hc=qc
,hc
指针后移一位,指向新插入的节点qc
。
使用尾插法,qc
是最后一个包含数据域的节点,因此hc->next==NULL
。多项式c
仍按照指数降序排列。
代码
int compare(Polyn a, Polyn b)//比较两个多项式每项的大小
{
if (a&&b) // 多项式a和b均不为空
{
if (a->expn > b->expn) return 1; // a的指数大于b的指数,返回1
else if (a->expn < b->expn) return -1; //a的指数小于b的指数,返回-1
else return 0; //a的指数等于b的指数,返回0
}
else if (!a&&b) return -1; //a为空,b不为空
else if (a&&!b) return 1; //b为空,a不为空
else if (!a&&!b)return 0; //a,b均为空
}
//一元稀疏多项式的加法和减法运算
Polyn addPolyn(Polyn a, Polyn b)
Polyn head ,qc;
Polyn qa = a->next;
Polyn qb = b->next;
Polyn hc=(Polyn)malloc(sizeof(Polynomial)); //新建节点 hc
hc->next = NULL;
head = hc; //头结点head指向 hc
while (qa || qb)
{
qc= (Polyn)malloc(sizeof(Polynomial)); //用来存贮计算出来的多项式c的每一项
if (compare(qa, qb) == 1) //多项式a的项的指数大于多项式b的项的指数
{
qc->coef = qa->coef; //a的该项直接作为c的一项
qc->expn = qa->expn;
qa = qa->next;
}
else if (compare(qa, qb) == 0) //指数相同,两项相加作为c的一项
{
qc->coef = qa->coef + qb->coef;
qc->expn = qa->expn ;
qa = qa->next;
qb = qb->next;
}
else //多项式a的项的指数小于多项式b的项的指数
{
qc->coef = qb->coef; //b的该项直接作为c的一项
qc->expn = qb->expn;
qb = qb->next;
}
if (qc->coef != 0) //将qc节点插入链表中
{
qc->next = hc->next;
hc->next = qc;
hc = qc; //hc后移一位,指向新插入的节点qc
}
else free(qc);
}
return head;
}
Polyn subPolyn(Polyn a, Polyn b) //多项式减法运算
{
Polyn h = b;
Polyn p = b->next;
while(p) //将b的每一项系数都取相反数
{
p->coef *= -1;
p = p->next;
}
Polyn head = addPolyn(a, h); //计算 a + (-b)
for (Polyn i = h->next; i != 0; i = i->next) //最后再将b的每项系数还原
{
i->coef *= -1;
}
return head;
}
3.一元稀疏多项式的打印和计算在x处的值
打印输出
按照这种格式 5x^8-3.1x^11+2x
进行打印输出。从头到尾遍历多项式,特殊处理系数为1
和-1
。系数为1
时,输出'x'
,为-1
时,输出'-x'
,为其他时输出x^,
或者 -x^
。然后在'x'
的后边将每项的指数格式输出。通过对系数和指数的情况分类讨论,正确输出+
号和-
号。具体思路见代码。
代码
void printPoLlyn(Polyn head)
{
Polyn q = head->next;
int flag = 0; //记录是否为第一项
if (!q)
{
puts("NULL(0)\t");
return;
}
while (q) //coef是系数,expn是指数
{
if (q->coef > 0 && flag == 1) //系数为正,且不为第一项
{
printf("+"); //输出加号
}
flag = 1;
if (q->coef != 1 && q->coef != -1) //系数不为-1或者1
{
printf("%g", q->coef); //输出系数
if (q->expn == 1) printf("x"); //指数为1,输出x
else if (q->expn != 0) printf("x^%d", q->expn);
}
else
{
if (q->coef == 1) //系数为1
{
if (q->expn == 0) printf("1"); //指数为0,按照常数1输出
else if (q->expn == 1) printf("x"); //指数为1,输出x
else printf("x^%d", q->expn);
}
if (q->coef == -1) //系数为-1
{
if (q->expn == 0) printf("-1");
else if (q->expn == 1) printf("-x");
else printf("-x^%d", q->expn);
}
}
q = q->next; //将q指针后移
}
printf("\t\t");
}
计算多项式在x的值
遍历要计算的多项式的每一项,定义一个临时变量tmp
。当该项的指数expn
不为0
时,如果为负数,我们进行tmp /= x, expn++
。如果为正数,我们进行tmp *= x, expn--
。重复上述操作,直到expn==0
时停止。最后将每一项的值累加起来,记录到sum
中,执行sum += p->coef*tmp
操作,便得到了多项式在x
处的值。
代码
double value(Polyn head, int x) //计算多项式在x处的值
{
double sum = 0;
for (Polyn p = head->next; p != 0; p = p->next) //遍历要计算的多项式
{
int tmp = 1; //临时变量 tmp用来存贮计算 x^a 或者 x^-a
int expn = p->expn;
while(expn != 0) //如果指数不为0,将一直执行下属操作
{
if (expn < 0) tmp /= x, expn++; //累乘运算
else if(expn>0) tmp *= x, expn--; //累除运算
}
sum += p->coef*tmp; //将每一项的值累加起来
}
return sum;
}