实验题目:多项式加法问题
实验目的:设计一个一元稀疏多项式简单计算器。实验内容与要求 一元稀疏多项式简单计算器的基本功能是: (1)输入并建立多项式; (2)输出多项式,输出形式为整数序列:n,c1,e1,c2,e2,…,cn,en,其中n是多项式的项数,ci和ei分别是第i项的系数和指数,序列按指数降序排列。 (3)多项式a与多项式b相乘,建立多项式。
实验思路:
最朴素的想法就是用两个数组来表示一个多项式,一个数组存放指数,另一个存放系数,下标相同代表同一项。当实现加法时,就需要寻找指数相同的项进行相加,把得到的结果存入另外一个数组当中去。当实现乘法是,我们就循环遍历两个式子,让他们每个项之间两两相乘,结果保存在另外一个数组中。
然而注意到是一元稀疏多项式,也就是可能存在这样的式子
f
(
x
)
=
10
x
1000
+
6
x
2
f(x) = 10x^{1000}+6x^{2}
f(x)=10x1000+6x2
那么我们必须至少用长度为1000的数组来存储,并且其中大多数数组的元素为零。这样算法的空间复杂度很高也很浪费。
因此决定使用链表这一数据结构来表示。
默认多项式一的长度为n,多项式二的长度为m。
实验步骤:
第一步:建立存储的链表
第一步我们需要定义一个链表,里面保存每一项的系数和指数。并且分别定义两个这样的链表,来表示需要相加的两个多项式。
实验代码
struct PolyNode
{
float coef; // 指数,考虑小数的情况
int expon; // 次数
struct PolyNode *link; // 后继节点
};
typedef struct PolyNode *Polynomial;
Polynomial p1, p2; //代表输入的两个多项式
第二步:明确读入数据并保存
我们的思路是,对于每个需要读入的多项式,首先读入项数。接着,按照指数的高低,分别读入。
专门写了一个ReadPoly()函数用来读取多项式
实验代码
Polynomial ReadPoly(int n1)
{
Polynomial P, rear, t;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
rear = P;
for (int i = 1; i <= n1; i++)
{
float c; int f;
printf("第%d项系数:", i); // 输入第i项系数
scanf("%f", &c);
printf("第%d项次数:", i); // 输入第i项次数
scanf("%d", &f);
Attach(c, f, &rear); // 链接成链表
}
t = P; P = P->link;
free(t);
return P;
}
时间复杂度
O
(
N
+
M
)
O(N+M)
O(N+M)
指针P 用来保存多项式的结果。如何将输入的每一组系数和指数联系起来,我们则需要用一个Attach函数去完成。
第三步:将读入的系数和指数连接起来
写一个Attach 函数,新开辟一个节点,将指数和系数保存到节点当中,再将节点连接到rear链表的后面。
实验代码
void Attach(int c, int e, Polynomial *pRear)
{
Polynomial p;
p = (Polynomial)malloc(sizeof(struct PolyNode)); // 开辟新节点
p->coef = c; // 系数
p->expon = e; // 次数
p->link = NULL;
(*pRear)->link = p;
*pRear = p;
}
第四步:进行排序
我们默认输入是随机的,可以不按照次数降序排列。因此需要一个排序的函数进行排序。
实验代码
Polynomial Sort(Polynomial pHead)//链表排序
{
Polynomial P = pHead;
Polynomial p = NULL;
Polynomial q = NULL;
int temp;
float tmp2;
// 冒泡排序
for (p= pHead; p != NULL; p = p->link)
{
for (q = p->link; q != NULL; q = q->link)
{
if (p->expon < q->expon)
{
// 分别交换系数和次数
temp = p->expon;
tmp2 = p->coef;
p->expon = q->expon;
p->coef = q->coef;
q->expon = temp;
q->coef = tmp2;
}
}
}
return pHead;
}
时间复杂度
O
(
N
M
)
O(NM)
O(NM)
第四步:进行相加
我们使用PolyAdd() 函数进行相加。逻辑如下:
首先开辟一个新的链表用来保存相加之后的结果。
比较两个多项式的每一项,如果相同就进行系数相加并且存入新的链表。如果第一个的指数大,那么第二个就向后移动一个;如果第一个的指数小,那么第一个就向后移动一个。
只要当p1和p2任何一个为空时,那么比较就结束,p1或p2剩余没有比较的部分就自动存到p3后面。
其中,Compare函数是用来比较次数的大小,如果相同,返回0;如果前者大返回1,后者大返回-1.
实验代码
Polynomial PolyAdd(Polynomial p1, Polynomial p2)
{
Polynomial Front, rear, temp;
float sum;
rear = (Polynomial)malloc(sizeof(struct PolyNode));
Front = rear;
while (p1&&p2) // 比较条件,都不为空
{
switch (Compare(p1->expon, p2->expon)) { // Compare 来比较大小
case 1:
Attach(p1->coef, p1->expon, &rear);
p1 = p1->link; // 前者比较大的情况
break;
case -1:
Attach(p2->coef, p2->expon, &rear);
p2 = p2->link; // 后者比较大的情况
break;
case 0:
sum = p1->coef + p2->coef;
if (sum) Attach(sum, p1->expon, &rear); // 相加
p1 = p1->link;
p2 = p2->link;
break;
}
}
for (; p1; p1 = p1->link) Attach(p1->coef, p1->expon, &rear); // 保存剩余项
for (; p2; p2 = p2->link) Attach(p2->coef, p2->expon, &rear); // 保存剩余项
rear->link = NULL; // 最后为空
temp = Front;
Front = Front->link;
free(temp);
return Front;
}
时间复杂度
O
(
m
a
x
(
N
,
M
)
)
O(max(N,M))
O(max(N,M))
第五步:进行相乘
与加法类似,首先开辟一个新的链表用来保存相乘之后的结果。
但是我们需要用两层循环,使得两个多项式中的每一项两两相乘运算。
最后将结果保存。
实验代码
Polynomial PolyMulti(Polynomial p1, Polynomial p2)
{
Polynomial front, rear, temp;
front = rear = (Polynomial)malloc(sizeof(struct PolyNode));
Polynomial t1, t2;
float product_coef; int product_expon;
if (!p1 || !p2) return NULL;
// 令每一项相乘
for (t1 = p2; t1; t1 = t1->link)
{
for (t2 = p1; t2; t2 = t2->link)
{
product_coef = (t1->coef)*(t2->coef);
product_expon = (t1->expon) + (t2->expon);
Attach(product_coef, product_expon, &rear);
}
}
temp = front;
front = front->link;
free(temp);
return front;
}
时间复杂度
O
(
N
M
)
O(NM)
O(NM)
第六步:输出
输出就非常简单了,重点是输出的格式问题。我是将格式统一为
c
o
e
f
e
x
p
o
n
coef \quad expon
coefexpon
直接看代码吧
相加输出代码
while (p3!=NULL)
{
printf("%.2f * x^%d", p3->coef, p3->expon);
p3 = p3->link;
if (p3 != NULL && p3->coef > 0)
printf("+");
}
时间复杂度
O
(
N
+
M
)
O(N+M)
O(N+M)
相乘输出代码
为了将次数一样的项合并,乘法的输出稍微复杂一点
float C = p4->coef;
int E = p4->expon;
p4 = p4->link;
if(p4==NULL)
printf("%.2f*x^%d ", C, E);
while (p4 != NULL)
{
int flag = 0;
while (p4->expon == E && p4!=NULL)
{
C += p4->coef;
if(p4->link!=NULL)
p4 = p4->link;
flag++;
}
printf("%.2f * x^%d ", C,E);
C = p4->coef;
E = p4->expon;
p4 = p4->link;
if (p4 != NULL && p4->coef > 0)
printf("+");
if(!p4)
if (C>0)
printf("+ %.2f * x^%d ", C, E);
else
printf("%.2f * x^%d ", C, E);
}
时间复杂度
O ( N M ) O(NM) O(NM)
时间复杂度分析
假设多项式一的项数是 n n n,多项式二的项数是 m m m。由于我的程序各个部分的函数都是独立的,没有什么嵌套的关系,因此时间复杂度就是各部分时间复杂度最大的那个。在本程序里,时间复杂度最高的就是排序和相乘的 O ( N M ) O(NM) O(NM),然而当输入是按照从高到低的次数进行输入的时候,排序的时间复杂度就可以降到 ( N ) (N) (N)
相乘的每两项相乘是不可避免的,因此本实验的时间复杂度为
O ( N M ) O(NM) O(NM)
运行截图
测试1:
多项式1:
f ( x ) = x 6 + 2 x 3 − 7 x 2 + 2 f(x) = x^6+2x^3-7x^2+2 f(x)=x6+2x3−7x2+2
多项式2:
f ( x ) = 3 x 4 − 4 x 3 + 2 x − 7 f(x) = 3x^4-4x^3+2x-7 f(x)=3x4−4x3+2x−7
结果:
相加
f
(
x
)
=
x
6
+
3
x
4
−
2
x
3
−
7
x
2
+
2
x
−
5
f(x) = x^6+3x^4-2x^3-7x^2+2x-5
f(x)=x6+3x4−2x3−7x2+2x−5
相乘
f ( x ) = 3 x 10 − 4 9 + 8 x 7 − 36 x 6 + 28 x 5 + 10 x 4 − 36 x 3 + 49 x 2 + 4 x − 14 f(x) = 3x^{10}-4^9+8x^7-36x^6+28x^5+10x^4-36x^3+49x^2+4x-14 f(x)=3x10−49+8x7−36x6+28x5+10x4−36x3+49x2+4x−14
测试结果:
测试2:
多项式1:
f
(
x
)
=
20
x
1000
−
7
f(x) = 20x^{1000}-7
f(x)=20x1000−7
多项式2:
f
(
x
)
=
x
2
+
1
f(x) = x^2+1
f(x)=x2+1
结果:
相加
f
(
x
)
=
2
0
1000
+
x
2
−
6
f(x) = 20^{1000}+x^2-6
f(x)=201000+x2−6
相乘
f
(
x
)
=
2
0
1002
+
2
0
1000
−
7
x
2
−
7
f(x) = 20^{1002}+20^{1000} -7x^2-7
f(x)=201002+201000−7x2−7
测试结果:
测试3:
多项式1:
f
(
x
)
=
0.2
x
2
+
0.1
x
1
f(x) = 0.2x^{2}+0.1x^1
f(x)=0.2x2+0.1x1
多项式2:
f
(
x
)
=
0.4
x
2
+
0.6
x
1
f(x) = 0.4x^2+0.6x^1
f(x)=0.4x2+0.6x1
结果:
相加
f
(
x
)
=
0.6
x
2
+
0.7
x
1
f(x) = 0.6x^{2}+0.7x^1
f(x)=0.6x2+0.7x1
相乘
f
(
x
)
=
0.08
x
4
+
0.16
x
3
+
0.06
x
2
f(x) = 0.08x^4+0.16x^3+0.06x^2
f(x)=0.08x4+0.16x3+0.06x2
测试结果:
心得体会
本次实验完成了稀疏多项式的乘法和加法,主要用了链表的操作和运算。在本次实验中,我学会了如何分析时间复杂度,让程序的运行效率更好;还学会了如何链表这一数据结构内在的层次逻辑,如何链接链表等等。对于链表而言,判断是否为空是非常重要的,如果没有判断链表为空会出现一定的错误,或者程序报错。
附录:完整代码
#include <stdio.h>
#include <stdlib.h>
struct PolyNode
{
float coef;
int expon;
struct PolyNode *link;
};
typedef struct PolyNode *Polynomial;
Polynomial p1, p2;
int num = 0;
void Attach(float c, int e, Polynomial *pRear)
{
Polynomial p;
p = (Polynomial)malloc(sizeof(struct PolyNode));
p->coef = c;
p->expon = e;
p->link = NULL;
(*pRear)->link = p;
*pRear = p;
}
int Compare(int c1, int c2)
{
if (c1 == c2)
return 0;
if (c1 > c2)
return 1;
else
return -1;
}
Polynomial PolyAdd(Polynomial p1, Polynomial p2)
{
Polynomial Front, rear, temp;
float sum;
rear = (Polynomial)malloc(sizeof(struct PolyNode));
Front = rear;
while (p1&&p2)
{
switch (Compare(p1->expon, p2->expon)) {
case 1:
Attach(p1->coef, p1->expon, &rear);
p1 = p1->link;
break;
case -1:
Attach(p2->coef, p2->expon, &rear);
p2 = p2->link;
break;
case 0:
sum = p1->coef + p2->coef;
if (sum) Attach(sum, p1->expon, &rear);
p1 = p1->link;
p2 = p2->link;
break;
}
}
for (; p1; p1 = p1->link) { Attach(p1->coef, p1->expon, &rear); }
for (; p2; p2 = p2->link) { Attach(p2->coef, p2->expon, &rear); }
rear->link = NULL;
temp = Front;
Front = Front->link;
free(temp);
return Front;
}
Polynomial PolyMulti(Polynomial p1, Polynomial p2)
{
Polynomial front, rear, temp;
front = rear = (Polynomial)malloc(sizeof(struct PolyNode));
Polynomial t1, t2;
float product_coef;
int product_expon;
if (!p1 || !p2) return NULL;
for (t1 = p2; t1; t1 = t1->link)
{
for (t2 = p1; t2; t2 = t2->link)
{
product_coef = (t1->coef)*(t2->coef);
product_expon = (t1->expon) + (t2->expon);
Attach(product_coef, product_expon, &rear);
}
}
temp = front;
front = front->link;
free(temp);
return front;
}
Polynomial ReadPoly(int n1)
{
Polynomial P, rear, t;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
rear = P;
for (int i = 1; i <= n1; i++)
{
float c; int f;
printf("第%d项系数:", i);
scanf("%f", &c);
printf("第%d项次数:", i);
scanf("%d", &f);
Attach(c, f, &rear);
}
t = P; P = P->link;
free(t);
return P;
}
Polynomial Sort(Polynomial pHead)//链表排序
{
Polynomial P = pHead;
Polynomial p = NULL;
Polynomial q = NULL;
int temp;
float tmp2;
for (p= pHead; p != NULL; p = p->link)
{
for (q = p->link; q != NULL; q = q->link)
{
if (p->expon < q->expon)
{
temp = p->expon;
tmp2 = p->coef;
p->expon = q->expon;
p->coef = q->coef;
q->expon = temp;
q->coef = tmp2;
}
}
}
return pHead;
}
int main()
{
int n1, n2;
Polynomial p5 = NULL;
Polynomial p6 = NULL;
Polynomial p7 = NULL;
printf("请输入多项式1的项数:\n");
scanf("%d", &n1);
printf("请分别输入多项式1的系数和次数:\n");
p1=ReadPoly(n1);
p1 = Sort(p1);
p5 = p1;
printf("请输入多项式2的项数:\n");
scanf("%d", &n2);
printf("请分别输入多项式2的系数和次数:\n");
p2=ReadPoly(n2);
p2 = Sort(p2);
p6 = p2;
Polynomial p3 = NULL;
Polynomial p4 = NULL;
p3 = PolyAdd(p1, p2);
p7= PolyMulti(p5, p6);
p4 = Sort(p7);
while (p3!=NULL)
{
num++;
p3 = p3->link;
}
p3 = PolyAdd(p1, p2);
printf("\n相加之后的多项式项数为:%d \n", num);
printf("\n相加之后的多项式为:\n");
while (p3!=NULL)
{
printf("%.2f %d ", p3->coef, p3->expon);
p3 = p3->link;
}
printf("\n相乘之后的多项式:\n");
float C = p4->coef;
int E = p4->expon;
p4 = p4->link;
if(p4==NULL)
printf("%.2f %d ", C, E);
while (p4 != NULL)
{
int flag = 0;
while (p4->expon == E && p4!=NULL)
{
C += p4->coef;
if(p4->link!=NULL)
p4 = p4->link;
flag++;
}
printf("%.2f %d ", C,E);
C = p4->coef;
E = p4->expon;
p4 = p4->link;
if(!p4)
printf("%.2f %d ", C, E);
}
}