数据结构实验(一)
时间:2022-05-11 06:35
数据结构实验(一):
一元多项式的乘法与加法运算
1.实验目的
熟练掌握链式线性表的基本操作,以及在多项式运算上的应用。
2.实验内容
设计函数分别求两个一元多项式的乘积与和。
3.实验要求
(1)输人说明:输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
(2)输出说明:输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。
(3)测试用例:
序号 | 输入 | 输出 | 说明 |
---|---|---|---|
1. | 请输入多项式非零项的个数:4 请以指数递降方式输入多项式非零项的系数和指数:3 4 -5 2 6 1 -2 0 请输入多项式非零项的个数:3 请以指数递降方式输入多项式非零项的系数和指数:5 20 -7 4 3 1 | 进行加法运算后的多项式的系数 和指数(以指数递降顺序输出): 5 20 -4 4 -5 2 9 1 -2 0 进行乘法运算后的多项式的系数和 指数(以指数递降顺序输出):15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1 | 一般情况 |
2. | 请输入多项式非零项的个数:2 请以指数递降方式输入多项式非零项的系数和指数:1 2 1 0 请输入多项式非零项的个数:2 请以指数递降方式输入多项式非零项的系数和指数:1 2 -1 0 | 进行加法运算后的多项式的系数 和指数(以指数递降顺序输出): 2 2 进行乘法运算后的多项式的系数和 指数(以指数递降顺序输出):1 4 -1 0 | 同类项合并时有抵消 |
3. | 请输入多项式非零项的个数:2 请以指数递降方式输入多项式非零项的系数和指数:-1000 1000 1000 0 请输入多项式非零项的个数:2 请以指数递降方式输入多项式非零项的系数和指数:1000 1000 -1000 0 | 进行加法运算后的多项式的系数 和指数(以指数递降顺序输出): 0 0 进行乘法运算后的多项式的系数和 指数(以指数递降顺序输出): -1000000 2000 2000000 1000 -1000000 0 | 结果有零多项式 |
4. | 请输入多项式非零项的个数:0 请以指数递降方式输入多项式非零项的系数和指数: 请输入多项式非零项的个数:1 请以指数递降方式输入多项式非零项的系数和指数:999 1000 | 进行加法运算后的多项式的系数 和指数(以指数递降顺序输出): 999 1000 进行乘法运算后的多项式的系数和 指数(以指数递降顺序输出):0 0 | 输入有零多项式和常数多项式 |
4.解决思路
(1)问题分析
由于多项式可能非常稀疏,所以宜采用链式线性表表示,仅存储非零项。又由于题目不仅要求计算乘积,还要求计算和式,所以在计算中不能破坏原始输入的两个多项式,需要建立新的链表存储结果多项式。
多项式的加法运算很简单,只要逐项比较两多项式的非零项,将指数较大的项加到结果多项式的末尾即可。这里要注意指数相同的项相加后系数为零的情况,以及零多项式的特殊处理。
对于两个多项式P1和P2相乘,可有两种求解思路:
①利用多项式的加法运算,即将多项式P2的每一项分别与P1多项式相乘,其结果也是一个多项式。应用多项式的加法运算,逐步将这些多项式累加,就可获得结果。
②直接运算,逐项插入。将多项式P2的每一项分别与P1各项相乘,将所乘形成的新项插人到中间结果多项式中。该中间结果多项式一开始为空,并以指数递减的顺序维持当前的运算中间状态。当有新项需要插人时,相当于在一个递减链表中插入一个新结点,并维持递减顺序。如果插入的新结点的指数与链表中某结点的指数一样,则将其系数相加;如果系数相加后的结果为零,则从中间结果链表中删除相应结点,否则就更改链表中系数值;如果不存在指数相同结点,则将新结点插入到相应位置。
(2)实现要点
不管是采用上述哪种方法,都需要使用一个链表P表示当前运算的中间状态(也是一个多项式),P一开始是空的。 如果直接使用多项式加法运算,则每次将P2的某项与Pl相乘的结果生成一个新多项式TmpP,然后将TmpP加到P中,使P保持目前的运算结果。如果采用直接插入各项的方法,则是将P2的某项与P1的某项相乘的结果(系数相乘,指数相加),按顺序插入到P中。
注意:采用模块化编程,将求和函数与求乘积函数分别实现,会带来很大方便。
5.实验思考题
本题以链表的方式表示多项式,读者可以改用数组的方式实现相应的多项式乘法与加法运算。
6.数据结构及相关函数说明
话不多说,先上代码:
#include
#include
?
typedef struct Node
{
int coef; //系数
int expon; //指数
struct Node* Next; //指向下一个节点的指针
}List;
typedef List* PtrToNode;
typedef List* Polynomial;
int con = 0;
//尾插
void Attach(int c, int e, PtrToNode* pRear);
?
//从标准输入中获得多项式
Polynomial GetPoly();
?
//输出
void PutPoly(Polynomial p);
?
//多项式加法
Polynomial PolyAdd(Polynomial p1, Polynomial p2);
?
//多项式乘法
Polynomial PolyMulti(Polynomial p1, Polynomial p2);
?
int main()
{
Polynomial p1 = GetPoly();
Polynomial p2 = GetPoly();
?
Polynomial pm = PolyMulti(p1, p2);
printf("乘法运算结果(指数递降方式输出系数和指数):");
PutPoly(pm);
?
printf("%c", ‘\n‘);
?
Polynomial pa = PolyAdd(p1, p2);
printf("加法运算结果(指数递降方式输出系数和指数):");
PutPoly(pa);
return 0;
}
?
Polynomial GetPoly()//得到多项式
{
int n;
con++;
printf("输入非零多项式(p%d)个数:",con);
scanf("%d", &n);
PtrToNode L, r, temp;
L = (PtrToNode)malloc(sizeof(List));
r = L;
printf("成对输入系数及指数(空格分开):\n");
for (int i = 0;i < n;i++)
{
temp= (PtrToNode)malloc(sizeof(List));
scanf("%d %d", &(temp->coef),&(temp->expon));
r->Next = temp;
r = temp;
}
r->Next = NULL;
L = L->Next;
return L;
}
?
void PutPoly(Polynomial p)//输出
{
if (p == NULL)
{
printf("0 0");
return;
}
else
{
printf("%d %d", p->coef, p->expon);
}
p = p->Next;
for (; p; p=p->Next)
{
printf(" %d %d", p->coef, p->expon);
}
}
//尾插法向单链表中存储数据
void Attach(int c, int e, PtrToNode* pRear)
{
PtrToNode p = (PtrToNode)malloc(sizeof(List));
p->coef = c;
p->expon = e;
p->Next = NULL;
?
(*pRear)->Next = p;
(*pRear) = p;
}
?
Polynomial PolyAdd(Polynomial p1, Polynomial p2)
{
PtrToNode L, r;
L = (PtrToNode)malloc(sizeof(List));
int sum;
r = L;
while (p1 && p2)
{
if (p1->expon > p2->expon)
{
Attach(p1->coef, p1->expon, &r);
p1 = p1->Next;
}
else if (p1->expon < p2->expon)
{
Attach(p2->coef, p2->expon, &r);
p2 = p2->Next;
}
else
{
sum = p1->coef + p2->coef;
if (sum) Attach(sum, p1->expon, &r);
p1 = p1->Next;
p2 = p2->Next;
}
}
for (;p1;p1 = p1->Next) Attach(p1->coef, p1->expon, &r);
for (;p2;p2 = p2->Next) Attach(p2->coef, p2->expon, &r);
r->Next = NULL;
L = L->Next;
return L;
}
?
Polynomial PolyMulti(Polynomial p1, Polynomial p2)
{
Polynomial p = NULL;
Polynomial t1;
Polynomial t2;
PtrToNode L, r;
for (t1 = p1;t1;t1 = t1->Next)
{
L = (PtrToNode)malloc(sizeof(List));
r = L;
for (t2 = p2;t2;t2 = t2->Next)
Attach(t1->coef * t2->coef, t1->expon + t2->expon, &r);
r->Next = NULL;
p = PolyAdd(p, L->Next);
}
return p;
}
/*******************************
对于部分编译器,以void命名的函数会产生
异常。例如:DEVC++
********************************/
?
7.实验结果抓图
(编辑器为DEVC++)
8.代码分析:
举例代码中均未加入头文件与主函数
(1)结构体分析
typedef struct Node
{
int coef; //系数
int expon; //指数
struct Node* Next; //指向下一个节点的指针
}List;
typedef List* PtrToNode;
typedef List* Polynomial;
int con = 0;
类型定义:typedef
typedef 原有类型名 新类型名:作用类似于重命名。例如:
typedef int ElementType;//用ElementType表示int
ElementType m = 8; //等价于int m = 8
这里typedef struct Node {...} List; 就是将结构体Node命名为List。
两句就是定义了两个结构体指针(List*)PtrToNode和Polynomial。
int con = 0;全局变量作用为了计数。
(2)主函数分析:
int main()
{
Polynomial p1 = GetPoly();
Polynomial p2 = GetPoly();
?
Polynomial pm = PolyMulti(p1, p2);
printf("乘法运算结果(指数递降方式输出系数和指数):");
PutPoly(pm);
?
printf("%c", ‘\n‘);
?
Polynomial pa = PolyAdd(p1, p2);
printf("加法运算结果(指数递降方式输出系数和指数):");
PutPoly(pa);
return 0;
}
?
主函数是解题思路,具体实现暂时不需要处理。
两次调用GetPoly()函数得到多项式的系数和指数,将其分别赋值给p1,p2;再调用多项式乘法函数PolyMulti()赋值给pm,将pm参数传入多项式输出PutPloy;加法同理。
建议用函数封装,不仅可以大大减少修改时的工作量,还有很多好处。
(3)自定义函数分析
(1)获得输入多项式系数及指数的函数GetPoly()
Polynomial GetPoly()//得到多项式
{
int n;
con++;
printf("输入非零多项式(p%d)个数:",con);
scanf("%d", &n);
PtrToNode L, r, temp;
L = (PtrToNode)malloc(sizeof(List));
r = L;
printf("成对输入系数及指数(空格分开):");
for (int i = 0;i < n;i++)
{
temp= (PtrToNode)malloc(sizeof(List));
scanf("%d %d", &(temp->coef),&(temp->expon));
r->Next = temp;
r = temp;
}
r->Next = NULL;
L = L->Next;
return L;
}
?
con 用于计数,为后续添加p3多项式提供了方便。
动态存储分配函数malloc
(指针类)变量名 =(函数返回类型)malloc(连续存储空间大小):此时函数返回类型需要与特定指针的变量类型一致。
申请成功变量指向分配内存空间的起始地址,未成功返回NULL。
例如
int *L;
L = (int *)malloc(sizeof(int));
用for循环读取多项式的系数及指数,赋值给结构体指针L,动态分配一段连续空间(malloc)之后形成链表。此时,L即为链表节点结构的指针。
链表:一种动态数据结构,在动态存储空间的操作中,C语言提供常用函数有malloc()和free()。
这里定义了三个结构体指针变量: L,r,temp。
初始状态,L和r指向同一个节点,改变r就改变L,每输入一组元素赋值都将其给r->Next,r = r->Next是指每输入一组元素让r指针指向后一个,最后r->Next = NULL,L = L->Next(指向链表的第一个元素)即构造了一个头结点指针为L,尾结点指针为r的链表。
(2)输出多项式系数及指数的函数PutPoly()
void PutPoly(Polynomial p)//输出
{
if (p == NULL)
{
printf("0 0");
return;
}
else
{
printf("%d %d", p->coef, p->expon);
}
p = p->Next;
for (; p; p=p->Next)
{
printf(" %d %d", p->coef, p->expon);
}
}
传入一个链头指针,p接收。p为空则表示输入非零多项式个数为0,输出便是0 0。
不为空,for循环链表直至表尾。将每一个值输出。
(3)尾插函数Attach(),向链表尾部加入元素
void Attach(int c, int e, PtrToNode* pRear)
{
PtrToNode p = (PtrToNode)malloc(sizeof(List));
p->coef = c;
p->expon = e;
p->Next = NULL;
?
(*pRear)->Next = p;
(*pRear) = p;
}
?
void Attach(int c, int e, PtrToNode* pRear) 参数:c是系数,e是指数,*pRear表尾指针。
每传入一个参数向表尾(*pRear->Next)加入。
(4)多项式相加函数PolyAdd()
Polynomial PolyAdd(Polynomial p1, Polynomial p2)
{
PtrToNode L, r;
L = (PtrToNode)malloc(sizeof(List));
int sum;
r = L;
while (p1 && p2)
{
if (p1->expon > p2->expon)
{
Attach(p1->coef, p1->expon, &r);
p1 = p1->Next;
}
else if (p1->expon < p2->expon)
{
Attach(p2->coef, p2->expon, &r);
p2 = p2->Next;
}
else
{
sum = p1->coef + p2->coef;
if (sum) Attach(sum, p1->expon, &r);
p1 = p1->Next;
p2 = p2->Next;
}
}
for (;p1;p1 = p1->Next) Attach(p1->coef, p1->expon, &r);
for (;p2;p2 = p2->Next) Attach(p2->coef, p2->expon, &r);
r->Next = NULL;
L = L->Next;
return L;
}
传入两个链表指针,链表中分别存储着两个多项式的数据。从高次向下比较次数(因为次数从高到低输入),若相等则系数相加,再调用Attach()函数尾插法插入到该函数(PloyAdd())内的链表L中,并返回。
(5)
Polynomial PolyMulti(Polynomial p1, Polynomial p2)
{
Polynomial p = NULL;
Polynomial t1;
Polynomial t2;
PtrToNode L, r;
for (t1 = p1;t1;t1 = t1->Next)
{
L = (PtrToNode)malloc(sizeof(List));
r = L;
for (t2 = p2;t2;t2 = t2->Next)
Attach(t1->coef * t2->coef, t1->expon + t2->expon, &r);
r->Next = NULL;
p = PolyAdd(p, L->Next);
}
return p;
}
双重循环,遍历两个链表里的每一个节点,系数相乘指数相加之后所得到的结果通过调用Attach()加入到空链表L里。
拓展:函数内定义的变量存活周期只在该函数内,函数外的变量只能通过指针改变。