@## 标题[TOC]多项式计算机:实现两个多项式的相加、相减及相乘计算,并输出升幂和降幂两种结果形式。
声明:
此博客所有内容均基于个人对数据结构的理解,仅供参考,若发现任何错误希望得到指点,衷心希望此内容对您有所帮助!接下来让我们一起来学习数据结构吧!
多项式计算机实现思想(路线):
多项式计算机实现有很多种方法,我们实现的方法是对同一个链表进行处理。链表的一个结点包括一个指针域和两个数据域如下:
typedef struct Node
{
Elemtype index;
Elemtype coefficient;
struct Node *next;
}Lnode,*LinkList;
index为指数,coefficient为系数,next指向下一个结点。所以我们就可以用一个链表实现所有的操作。
我们的路线是(以下每一个操作均用函数实现):
-
先生成第一个指数递增的多项式
-
计算过程:逐个输入第二个多项式的每一项并和第一个多项式进行不同的处理
-
加法:利用加法函数使第二个多项式的每一项与第一个多项式相加
-
减法:利用减法函数使第二个多项式的每一项与第一个多项式相减
-
乘法:利用乘法函数使第二个多项式的每一项与第一个多项式的所有项相乘
以上处理后,处理结果均存储于同一个链表中,在此链表中的多项式,存在着系数为零的项以及指数为零的项,我们知道系数为零则此项值为零无意义,指数为零则为常数项。下面我们对这个链表(多项式)进行统一处理。
-
-
多项式处理:主要是删除系数为0的结点和把指数为0的结点(常数项)的系数求和并提取出来。
-
输出处理:升序和降序两种结果输出
-
利用升序结果输出函数(常数项在第一个)
-
利用 逆置函数将指数递增变为指数递减排序
-
利用降序结果输出函数(常数项在最后一个)
在处理时,需要以易读形式输出。所以要考虑系数的正负,以及常数项的输出的先后问题。
-
1生成第一个指数递增的多项式
1.1单次插入函数的实现,即每次输入一项,并存储到链表中。
/*在有序单链表中插入(加法)元素,链表仍然有序(默认升序),插入成功返回OK,插入失败返回ERROR*/
Status Insert_Linklist_add(LinkList L, Elemtype x, Elemtype y)
{
LinkList p, q, temp;
p = L; //备份头指针
Init_Linklist(temp); //创建新结点
temp->index = x; //将指数存入新结点
temp->coefficient = y; //将系数存入新结点
temp->next = NULL; //新结点指针域设为空
while(p->next){ //循环遍历寻找合适位置
q = p->next; //q为对比结点
if(x < q->index){ //若 新结点指数小于对比结点的指数(默认升序)
temp->next = p->next; //将结点插入其(对比结点)前
p->next = temp;
return OK; //结束函数
}else if(x == q->index){ //若 新结点与对比结点指数相同,使对比结点系数为两者系数之和
q->coefficient = q->coefficient + temp->coefficient;
return OK;
}else{ //否则 向后移位
p = p->next;
}
}
Init_Linklist(temp);//如果长度为0,则新结点为的第一个结点,否则新结点接在最后
temp->index = x;
temp->coefficient = y;
temp->next = NULL;
p->next = temp;
return OK;
}
通过利用上述函数,在升序表中插入元素仍可以保持升序状态(指数递增形式:通过对比指数的方式,实现了多项式的指数递增)。当插入元素的指数与所对比的元素的指数相同时,则将插入元素的系数加到对比元素的系数上,保证了多项式中无指数相同的项。
1.2生成指数递增形式的多项式
/*创建指数递增多项式(单链表)*/
Status CreatOrder_Linklist(LinkList &L)
{
Elemtype x, y; //x为指数,y为系数
Init_Linklist(L); //创建头结点,初始化空表
L->next = NULL; //单链表的长度为0
printf("请顺序输入系数与指数(注意:数据成对输入),当系数输入为0时停止输入\n");
while(scanf("%d%d", &y, &x) == 2 && y != 0)
Insert_Linklist_add(L, x, y); //单次插入(函数)
return OK;
}
此函数利用了上一个单次插入函数,此函数主要是初始化了一个链表,用于计算以及存储结果。另外,加了一个while循环用于多项式每一项的输入。
附:
/*初始化空表*/
Status Init_Linklist(LinkList &L)
{
L = (LinkList)malloc(sizeof(Lnode));//分配空间,并由LinkList类型输出。
if(!L) return ERROR; //异常处理
L->next = NULL; //表明这是一个空表
return OK;
}
2计算过程
2.1加法实现
加法实现比较简单,只需要把第二个多项式逐个插入第一个多项式中即可。
(主函数部分)
case 1:
printf("请输入被加数(多项式)\n");
if(CreatOrder_Linklist(La)) //输入第一个多项式,CreatOrder_Linklist(La)返回值为1
printf("单链表创建成功\n");
else
printf("单链表创建失败\n");
printf("请输入加数(多项式)\n");
printf("请顺序输入系数与指数(注意:数据成对输入),系数输入0停止输入\n");
while(scanf("%d%d", &y, &x) == 2 && y != 0) //输入第二个多项式(含结束条件)
Insert_Linklist_add(La, x, y); //加法函数,逐个加入到第一个多项式中
2.2减法实现
减法和加法实现差别,仅在于用于单次插入函数中一个符号的不同,即在系数相等时将系数相加改为系数相减即可。修改部分在下面代码中已做标记。
修正:对于最后指数最大的多项式未进行“负值”(在系数前加一个负号)。
/*减法插入*/
Status Insert_Linklist_subt(LinkList L, Elemtype x, Elemtype y)
{
LinkList p, q, temp;
p = L; //备份头指针
Init_Linklist(temp); //创建新结点
temp->index = x; //将指数存入新结点
temp->coefficient = y; //将系数存入新结点并置为负
temp->next = NULL; //新结点指针域设为空
while(p->next){ //循环遍历寻找合适位置
q = p->next; //q为对比结点
if(x < q->index){ //若 新结点指数小于对比结点指数(默认升序)
temp->next = p->next; //将结点插入其(对比结点)前
p->next = temp;
return OK; //结束函数
}else if(x == q->index){ //若 新结点指数与对比结点相同,则使对比结点系数为对比结点系数减去新结点系数之差
/**修改部分**/q->coefficient = q->coefficient - temp->coefficient;/**修改部分**/
return OK; //结束函数
}else //否则 向后移位(继续寻找)
p = p->next;
}
Init_Linklist(temp); //如果单链表的长度为0,则新结点为单链表的第一个结点/亦或上述条件不满足时,将新结点结在后面
temp->index = x;
temp->coefficient = -y; //(修改处)负值处理
temp->next = NULL;
p->next = temp;
return OK;
}
主函数部分如下:
(主函数部分)
case 2:
printf("请输入被减数(多项式)\n");
if(CreatOrder_Linklist(La))//输入第一个多项式(CreatOrder_Linklist(La)返回值为1)
printf("单链表创建成功\n");
else
printf("单链表创建失败\n");
printf("请输入减数(多项式)\n");
printf("请顺序输入系数与指数(注意:数据成对输入),系数输入0停止输入\n");
while(scanf("%d%d", &y, &x) == 2 && y != 0) //输入第二个多项式(含结束条件)
Insert_Linklist_subt(La, x, y); //减法函数,逐个与第一个多项式相减
2.3乘法实现
/错误思路/:乘法实现过程相较于加法和减法则更容易实现也更容易理解,即将第二个多项式的每一项与第一个多项式的所有项相乘即可。只需使第一个多项式每一项的系数与第二个多项式所有项的系数相乘并求和;使第一个多项式每一项的指数与第二个多项式所有项的系数相加。因为第一个多项式本身就是指数递增,那么加上相同的指数和,得到的多项式仍然是指数递增形式的。
/修改后/: 上面的乘法实现过程是错误的,我出现了比较严重的计算逻辑错误,在这里向大家说声抱歉! 在计算的过程中不可以改变La中存储的数据(第一个多项式),因为第二个多项式的每一项都必须与第一个多项式的所有项相乘并最终相加,如果在计算的过程中改变了第一个多项式的数据,那么计算就已经失败了。所以我们在创建一个新表Lb,将第二个多项式每一项与第一个多项式每一项相乘的结果都以相加的形式(使用加法函数)插入到Lb中,那么Lb就是我们需要的结果。然后对Lb进行处理和输出即可。
乘法函数代码如下:
/*乘法插入*/
Status Insert_Linklist_multip(LinkList La, LinkList Lb, Elemtype x, Elemtype y) {
LinkList p;
p = La->next;
while(p){
Insert_Linklist_add(Lb, x+p->index, y*p->coefficient); //加法操作(将结果逐个插入Lb内)
p = p->next;
}
}
主函数部分如下:
case 3:
Init_Linklist(Lb); //生成链表Lb的头节点(初始化空表)
printf("请输入被乘数(多项式)\n");
if(CreatOrder_Linklist(La)) //输入第一个多项式
printf("单链表创建成功\n");
else
printf("单链表创建失败\n");
printf("请输入乘数(多项式)\n");
printf("请顺序输入系数与指数(注意:数据成对输入),系数输入0停止输入\n");
while(scanf("%d%d", &y, &x) == 2 && y != 0) //输入第二个多项式
Insert_Linklist_multip(La, Lb, x, y); //乘法函数
小结:以上就是实现计算部分,但是实际是系数为零的项无意义,指数为零的项为常数项,所以我们必须对此进行处理。
3多项式的处理
主要是删除系数为0的结点和把指数为0的结点(常数项)的系数求和并提取出来。
/*删除系数为零的结点,并将常数项(指数为零)求和,返回变量count中*/
void DelEven_Linklist_coeff(LinkList L, Elemtype &count)
{
LinkList p, q;
p = L; //备份头指针
q = L->next; //q为操作结点
while(q){ //循环处理(封闭指针)
if(q->coefficient == 0){ //若 系数是为0
p->next = q->next; //使此结点的前驱指向后继
free(q); //释放此结点
q = p->next ; //向后移位
}else if(q->index == 0){ //若 指数为0(此项为常数项)
count += q->coefficient; //求常数项
p->next = q->next; //使此结点的前驱指向后继
free(q); //释放此结点
q = p->next; //向后移位
}else{ //否则 系数和指数都不为0
p = p->next; //向后移位
q = p->next;
}
}
}
遍历多项式的每一项,删除系数为0的项,以及将指数为0的项(常数项)求和并保存在count变量中。
4输出处理
升序和降序两种结果输出:
-
利用升序结果输出函数(常数项在第一个)
-
利用 逆置函数将指数递增变为指数递减排序
-
利用降序结果输出函数(常数项在最后一个)
在处理时,需要以易读形式输出。所以要考虑系数的正负,以及常数项的输出的先后问题。
4.1升序函数
/*升序结果输出(常数项置前)*/ Status Disp_Linklist_A(LinkList L, Elemtype count) { L = L->next; //L指向第一个结点 if(count != 0){ //若 常数项不为零 printf("%d", count); //直接先输出常数项 while(L) //接着输出每一项 { if(L->coefficient > 0) //若 系数为正则加"+"符号 printf("+%dx%d", L->coefficient, L->index); //输出 else //否则 系数为负正常输出 printf("%dx%d", L->coefficient, L->index); //输出 L = L->next; //向后移位 } }else{ //否则 常数项为零 if(L == NULL){ //若 第一个结点不存在(结果为零) printf("计算结果为:0\n"); return OK; //结束函数 }else{ //否则 第一个结点存在 printf("%dx%d",L->coefficient, L->index); //输出第一个结点 L = L->next; //向后移位 while(L) //逐个输出 { if(L->coefficient > 0) //若系数为正,加"+"符号 printf("+%dx%d", L->coefficient, L->index); else //否则系数为负正常输出 printf("%dx%d", L->coefficient, L->index); L = L->next; //向后移位 } } } printf("\n"); return OK; }
升序结果输出函数轮廓如下:
— 若 常数项不为0
———— 输出常数项
———— 输出每一项:
—————— 若 系数为正,则输出前加“+”符号。
—————— 否 系数为负,则直接输出。(负数自带符号“-”)
— 否 常数项为0
———————— 若 多项式链表为空,
——————————— 输出结果0,结束函数
———————— 否 多项式链表不为空
——————————— 输出第一项
——————————— 输出余下项:
——————————————— 若 系数为正,则输出前加“+”符号。
——————————————— 否 系数为负,则直接输出。(负数自带符号“-”)
4.2多项式的逆置(单链表的逆置)
利用头插法实现单链表的逆置,即多项式有指数递变为指数递减形式,用于降序结果输出。
/*单链表逆置*/ void Reverse_Linklist(LinkList L) { LinkList p, q; p = L->next; //p指向第一个结点 L->next = NULL; while(p){ q = p; //p为操作结点 p = p->next; //将操作p向后移位 q->next = L->next; //将操作结点的指针域指向原来的第一个节点(头结点的后继) L->next = q; //将操作结点做为头节点的后继 //(将头结点的指针域的指针指向操作节点) } }
4.3降序结果输出
降序结果输出和升序差别并不大,主要在于多了一个链表的逆置,以及常数项输出先后的问题。
/*降序结果输出(常数项置后)*/ Status Disp_Linklist_D(LinkList L, Elemtype count) { Reverse_Linklist(L); //逆置 L = L->next; if(count != 0){ //若 常数项不为零 if(L == NULL) { printf("%d", count); return OK; } printf("%dx%d", L->coefficient, L->index); //先输出第一个结点 L= L->next; //向后移位 while(L) //逐个输出所有结点 { if(L->coefficient > 0) printf("+%dx%d", L->coefficient, L->index); else printf("%dx%d", L->coefficient, L->index); L = L->next; } //所有结点输出后 if(count > 0) //若 常数项大于零 printf("+%d", count); else //否 常数项小于零 printf("%d", count); }else{ //否 常数项为零 if(L == NULL){ //若多项式也为空,输出0结果,结束函数 printf("计算结果为:0\n"); return OK; } printf("%dx%d",L->coefficient, L->index);//输出第一个结点 L = L->next; while(L) //顺序输出所有结点 { if(L->coefficient > 0) printf("+%dx%d", L->coefficient, L->index); else printf("%dx%d", L->coefficient, L->index); L = L->next; } printf("\n"); return OK; } }
降序结果输出函数轮廓如下:
—若 常数项不为0
———— 若多项式链表为空
—————————— 输出常数项,结束函数
———— 输出第一项
———— 输出余下项:
——————— 若 系数为正,则输出前加“+”符号。
——————— 否 系数为负,则直接输出。(负数自带符号“-”)
———— 输出常数项:
——————— 若 常数项为正,则输出前加“+”符号。
——————— 否 常数项为负,则直接输出。(负数自带符号“-”)
—否 常数项为0
———— 若 多项式链表为空,
———————————输出结果0,结束函数
———— 否 多项式链表不为空
———————————输出第一项
———————————输出余下项:
————————————————若 系数为正,则输出前加“+”符号。
————————————————否 系数为负,则直接输出。(负数自带符号“-”)
暂无总结,待续。。。
附:主函数
int main() { Elemtype choice, x, y, count = 0; //choice为操作选项,x为输入指数,y为输入系数 LinkList La, Lb; //La为操作的多项式,所有计算均在此中完成 while(1) { menu(); //菜单 printf("选择你的操作:"); scanf("%d",&choice); //输入需要的操作 switch(choice) { case 1: //两个多项式的加法计算 printf("请输入被加数(多项式)\n"); if(CreatOrder_Linklist(La)) //输入第一个多项式(CreatOrder_Linklist(La)函数返回值为1) printf("单链表创建成功\n"); else printf("单链表创建失败\n"); printf("请输入加数(多项式)\n"); printf("请顺序输入系数与指数(注意:数据成对输入),系数输入0停止输入\n"); while(scanf("%d%d", &y, &x) == 2 && y != 0) //输入第二个多项式(含结束条件) Insert_Linklist_add(La, x, y); //加法函数,逐个加入到第一个多项式中 DelEven_Linklist_coeff(La, count); //删除系数为零的结点并将常数项(指数为零)返回count printf("升序结果为:\n"); Disp_Linklist_A(La, count); //升序结果输出 printf("降序结果为:\n"); Disp_Linklist_D(La, count); //降序结果输出 break; case 2: printf("请输入被减数(多项式)\n"); if(CreatOrder_Linklist(La)) //输入第一个多项式(CreatOrder_Linklist(La)函数返回值为1) printf("单链表创建成功\n"); else printf("单链表创建失败\n"); printf("请输入减数(多项式)\n"); printf("请顺序输入系数与指数(注意:数据成对输入),系数输入0停止输入\n"); while(scanf("%d%d", &y, &x) == 2 && y != 0) //输入第二个多项式(含结束条件) Insert_Linklist_subt(La, x, y); //减法函数,逐个与第一个多项式相减 DelEven_Linklist_coeff(La, count); //删除系数为零的结点并将常数项(指数为零)返回count printf("升序结果为:\n"); Disp_Linklist_A(La, count); //升序结果输出 printf("降序结果为:\n"); Disp_Linklist_D(La, count); //降序结果输出 break; case 3: Init_Linklist(Lb); //初始化空表 printf("请输入被乘数(多项式)\n"); if(CreatOrder_Linklist(La)) //输入第一个多项式(CreatOrder_Linklist(La)函数返回值为1) printf("单链表创建成功\n"); else printf("单链表创建失败\n"); printf("请输入乘数(多项式)\n"); printf("请顺序输入系数与指数(注意:数据成对输入),系数输入0停止输入\n"); while(scanf("%d%d", &y, &x) == 2 && y != 0) //输入第二个多项式(含结束条件) Insert_Linklist_multip(La, Lb, x, y); //乘法函数 DelEven_Linklist_coeff(Lb, count); //删除系数为零的结点并将常数项(指数为零)返回count Disp_Linklist_A(Lb, count); //结果输出 printf("降序结果为:\n"); Disp_Linklist_D(Lb, count); //结果输出 break; case 0: return 0; default: printf("输入错误,请重新输入\n"); } } }