实验题目:多项式加法问题
实验目的:设计一个一元稀疏多项式简单计算器。实验内容与要求 一元稀疏多项式简单计算器的基本功能是: (1)输入并建立多项式; (2)输出多项式,输出形式为整数序列:n,c1,e1,c2,e2,…,cn,en,其中n是多项式的项数,ci和ei分别是第i项的系数和指数,序列按指数降序排列。 (3)多项式a与多项式b相乘,建立多项式。
实验思路:
最朴素的想法就是用两个数组来表示一个多项式,一个数组存放指数,另一个存放系数,下标相同代表同一项。当实现加法时,就需要寻找指数相同的项进行相加,把得到的结果存入另外一个数组当中去。当实现乘法是,我们就循环遍历两个式子,让他们每个项之间两两相乘,结果保存在另外一个数组中。
然而注意到是一元稀疏多项式,也就是可能存在这样的式子
那么我们必须至少用长度为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;
}
时间复杂度
指针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;
}
时间复杂度
第四步:进行相加
我们使用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;
}
时间复杂度
第五步:进行相乘
与加法类似,首先开辟一个新的链表用来保存相乘之后的结果。
但是我们需要用两层循环,使得两个多项式中的每一项两两相乘运算。
最后将结果保存。
实验代码
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;
}
时间复杂度
第六步:输出
输出就非常简单了,重点是输出的格式问题。我是将格式统一为
直接看代码吧
相加输出代码
while (p3!=NULL)
{
printf("%.2f * x^%d", p3->coef, p3->expon);
p3 = p3->link;
if (p3 != NULL && p3->coef > 0)
printf("+");
}
时间复杂度
相乘输出代码
为了将次数一样的项合并,乘法的输出稍微复杂一点
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);
}
时间复杂度
时间复杂度分析
假设多项式一的项数是,多项式二的项数是。由于我的程序各个部分的函数都是独立的,没有什么嵌套的关系,因此时间复杂度就是各部分时间复杂度最大的那个。在本程序里,时间复杂度最高的就是排序和相乘的,然而当输入是按照从高到低的次数进行输入的时候,排序的时间复杂度就可以降到
相乘的每两项相乘是不可避免的,因此本实验的时间复杂度为
运行截图
测试1:
多项式1:
多项式2:
结果:
相加
相乘
测试结果:
测试2:
多项式1:
多项式2:
结果:
相加
相乘
测试结果:
测试3:
多项式1:
多项式2:
结果:
相加
相乘
测试结果:
心得体会
本次实验完成了稀疏多项式的乘法和加法,主要用了链表的操作和运算。在本次实验中,我学会了如何分析时间复杂度,让程序的运行效率更好;还学会了如何链表这一数据结构内在的层次逻辑,如何链接链表等等。对于链表而言,判断是否为空是非常重要的,如果没有判断链表为空会出现一定的错误,或者程序报错。
附录:完整代码
#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);
}
}