本文主要供初学者参考借鉴,欢迎大家一起讨论学习。
描述语言:C语言
抽象数据类型:
以下对于抽象数据类型一元多项式的定义参考清华《数据结构》教材。
读者可以以此为参考,本人在具体实现中加入了自己的风格,且主要是实现了递减特性和添项、相加、相乘的功能。
ADT Polynomical {
数据对象:D = {ai属于Termset, i = 1,2,...,m, m>=0
Termset中的每个元素包含一个表示系数的整数和表示指数的整数}
数据关系:R1 = {<ai-1,ai>|ai-1,ai属于D,且ai-1中的指数值 > ai中的指数值,i=2,...,n}
基本操作:
CreatPolyn(&P,m)
操作结果:输入m项的系数和指数,建立一元多项式P
DestoryPolyn(&P)
初始条件:一元多项式P已存在
操作结果:销毁一元多项式P
PrintPolyn(P)
初始条件:一元多项式P已存在
操作结果:打印一元多项式P
PolynLength(P)
初始条件:一元多项式P已存在
操作结果:返回一元多项式P中项数
AddPolyn(&Pa,&Pb)
初始条件:一元多项式Pa和Pb已存在
操作结果:完成多项式相加
SubtractPolyn(&Pa,&Pb)
初始条件:一元多项式Pa和Pb已存在
操作结果:完成多项式相减
MultiplyPolyn(&Pa,&Pb)
初始条件:一元多项式Pa和Pb已存在
操作结果:完成多项式相乘
}ADT Polynomical
多项式链表的表示:
typedef struct _polynomical {
int coe;//系数 coefficient
int expo;//指数 exponent
struct _polynomical *next;//切记 struct
struct _polynomical *prev;//切记 struct
} polynomical;
typedef struct _poly {
unsigned size;//项数
polynomical *head;
polynomical *tail;
} Poly;
*注:此表示方法以便于程序扩展与完善为目的进行设计。
1、将头指针放在一个结构内:相较于给函数传二级指针(ElemType**head)的方法更方便。并且此结构可以包含链表的其他信息,便于程序扩展(如添加尾指针tail,链表长度size)
2、本人还在节点(结点)的结构中加了指向直接前驱元素的指针域,即为双向链表,但在之后暂时没用上,供读者发挥(删除也无妨)
建立接口(函数):
//初始化多项式
Poly poly_creat(void);
//向已有多项式添加项
void poly_add(Poly *pPoly);
//显示多项式
void poly_print(const Poly *pPoly);
//清空多项式
void poly_free(Poly *pPoly);
//多项式相加
Poly poly_combine(Poly *pPoly1, Poly *pPoly2);
//多项式相乘
Poly poly_multiply(Poly *pPoly1, Poly *pPoly2);
此段代码加入了我本人的一些风格,仅供参考讨论,以下为详细分析
实现接口:
之前的“多项式链表的表示”和“建立接口(函数)”可放在一个头文件"polynomical.h"内。
以下为“polynomical.c”中内容:
1、初始化多项式
常规操作
Poly poly_creat(void){
Poly temp;
temp.size = 0;
temp.head = NULL;
temp.tail = NULL;
return temp;
}
2、向已有多项式添加项
本人为多项式链表添加了按指数递减的排列特点。
关键1:合并同类项(不要忽略对size的处理)
关键2:将新的项放在原链表合适位置(确保按指数递减排列)
(此代码有部分重复内容,可以进一步优化)
void poly_add(Poly *pPoly){
polynomical *poly_temp;
bool isFound = false;
//创建新的项
poly_temp = (polynomical *) malloc (sizeof(polynomical));
printf("Enter the coefficient:\n");
scanf("%d", &poly_temp->coe);
//若系数为 0,直接退出
if (poly_temp->coe == 0) {
printf("This item is already 0!\n");
return;
}
printf("Enter the exponent:\n");
scanf("%d", &poly_temp->expo);
poly_temp->next = NULL;
poly_temp->prev = NULL;
//链接到多项式
if (pPoly->size) {
polynomical *this;
//查找并合并同类项
for (this = pPoly->head; this; this = this->next) {
if (this->expo == poly_temp->expo) {
this->coe += poly_temp->coe;
isFound = true;
break;
}
}
//没有同类项则插入在合适位置
if (!isFound) {
polynomical *insert;//将会指向待插入项的后一项
// for 循环确定 insert 位置
for (insert = pPoly->head; insert && insert->expo > poly_temp->expo; insert = insert->next);
// 将 poly_temp 放在 insert 和 insert 前一项之间
// 注意 insert 为 NULL 的情况
// 注意插入到第一项的情况
if (insert && insert->prev == NULL) {//若插入到第一项
pPoly->head = poly_temp;
insert->prev = poly_temp;
poly_temp->next = insert;
poly_temp->prev = NULL;
}else if (insert) {
polynomical *node_temp;
node_temp = insert->prev;
insert->prev = poly_temp;
poly_temp->next = insert;
poly_temp->prev = node_temp;
node_temp->next = poly_temp;
}else{// insert 为 NULL 时直接添加在尾部
pPoly->tail->next = poly_temp;
poly_temp->prev = pPoly->tail;
pPoly->tail = poly_temp;
}
}
}else{
pPoly->head = poly_temp;
pPoly->tail = poly_temp;
}
//注意合并同类项后不要加 size
if (!isFound)
pPoly->size ++;
}
3、显示(打印)多项式
本人考虑了一点显示的美观:
显示方式:
代码:
void poly_print(const Poly *pPoly){
polynomical *this = pPoly->head;
if (!this) {
printf("The poly is 0.\n");
return;
}
for (; this; this = this->next) {
printf("%dx^(%d)", this->coe, this->expo);
//注意 this -> next 为 NULL 的情况
if (this->next && this->next->coe > 0) {
printf("+");
}
}
putchar('\n');
}
4、清空多项式
常规操作:依次free
void poly_free(Poly *pPoly){
polynomical *cur, *nex;
for (cur = pPoly->head; cur; cur = nex) {
nex = cur->next;
free(cur);
}
}
5、多项式相加
在相加和相乘功能的实现上,本人与清华《数据结构》上的处理稍有不同。
清华《数据结构》:Pa = Pa + Pb,在原多项式上进行修改,销毁Pb。返回void
本人:Pc = Pa + Pb,保留Pa与Pb,新建Pc。返回Poly
但归并算法的思路差不多:
1)两个指针分别指向两个多项式
2)第一个while同时考虑两个多项式:每次从两个多项式中选出合适的项(符合递减特性)添加到新多项式中,直到其中一个多项式的项遍历完为止。
3)处理另一个多项式中剩余的项
!!!注意:
1)合并同类项(size的处理不可疏忽)
2)此代码仍有优化空间(类似的地方本人直接采取了拷贝【擦汗】)
Poly poly_combine(Poly *pPoly1, Poly *pPoly2){
//创建新多项式存储多项式的和
//!!!切记初始化
Poly res = poly_creat();
polynomical *this1 = pPoly1->head, *this2 = pPoly2->head;
polynomical *temp;
while (this1 && this2) {
if (this1->expo > this2->expo) {
//新建一个节点并拷贝需要的结构
temp = (polynomical *) malloc (sizeof(polynomical));
temp->expo = this1->expo;
temp->coe = this1->coe;
temp->next = NULL;
temp->prev = NULL;
//链接
if (res.head) {
temp->prev = res.tail;
res.tail->next = temp;
res.tail = temp;
}else{
res.head = temp;
res.tail = temp;
}
this1 = this1->next;
}else if (this1->expo < this2->expo) {
//操作同上
temp = (polynomical *) malloc (sizeof(polynomical));
temp->expo = this2->expo;
temp->coe = this2->coe;
temp->next = NULL;
temp->prev = NULL;
if (res.head) {
temp->prev = res.tail;
res.tail->next = temp;
res.tail = temp;
}else{
res.head = temp;
res.tail = temp;
}
this2 = this2->next;
}else {
temp = (polynomical *) malloc (sizeof(polynomical));
*temp = *this1;
//指数不要相加
temp->coe += this2->coe;
temp->next = NULL;
temp->prev = NULL;
if (res.head) {
temp->prev = res.tail;
res.tail->next = temp;
res.tail = temp;
}else{
res.head = temp;
res.tail = temp;
}
this1 = this1->next; this2 = this2->next;
}
res.size++;
}
//处理 pPoly1 尾部数据
while (this1) {
temp = (polynomical *) malloc (sizeof(polynomical));
*temp = *this1;
temp->next = NULL;
temp->prev = NULL;
if (res.head) {
temp->prev = res.tail;
res.tail->next = temp;
res.tail = temp;
}else{
res.head = temp;
res.tail = temp;
}
this1 = this1->next;
res.size++;
}
//处理 pPoly2 尾部数据
while (this2) {
temp = (polynomical *) malloc (sizeof(polynomical));
*temp = *this2;
temp->next = NULL;
temp->prev = NULL;
if (res.head) {
temp->prev = res.tail;
res.tail->next = temp;
res.tail = temp;
}else{
res.head = temp;
res.tail = temp;
}
this2 = this2->next;
res.size++;
}
return res;
}
6、多项式相乘
可以将两个多项式相乘转化为一系列多项式相加:
//多项式相乘:
//分解为一系列加法运算
Poly poly_multiply(Poly *pPoly1, Poly *pPoly2){
Poly res = poly_creat();
polynomical *this1 = pPoly1->head, *this2 = pPoly2->head;
polynomical *temp;
if (!this1 || !this2) {
return res;
}
while (this2) {
Poly trans = poly_creat();
//将 A 中每一项依次乘以 B 中某一项
while (this1) {
//将每对相乘后存入 temp
temp = (polynomical *) malloc (sizeof(polynomical));
temp->coe = this1->coe * this2->coe;
temp->expo = this1->expo + this2->expo;
temp->prev = NULL;
temp->next = NULL;
//链接到 trans
if (trans.head) {
temp->prev = trans.tail;
trans.tail->next = temp;
trans.tail = temp;
}else{
trans.head = temp;
trans.tail = temp;
}
this1 = this1->next;
}
//每次完成后重置 this1
this1 = pPoly1->head;
//递增 this2
this2 = this2->next;
//更新结果
res = poly_combine(&res, &trans);
// trans 归零
poly_free(&trans);
}
return res;
}
main()中测试
#include <stdio.h>
#include <stdlib.h>
#include "polynomical.h"
void clearEnter(void);
void choice_list(void);
int main(int argc, char *argv[]){
Poly poly1 = poly_creat();
Poly poly2 = poly_creat();
Poly poly3 = poly_creat();
Poly poly4 = poly_creat();
char choice = 'y';
//创建两个多项式
printf("NOW >>>>> poly1:\n");
do{
poly_add(&poly1);
clearEnter();
printf("Continue?(y or n)\n");
scanf("%c", &choice);
} while (choice != 'n');
printf("The poly1:\n");
poly_print(&poly1);
printf("The size of the poly1: %u\n", poly1.size);
printf("NOW >>>>> poly2:\n");
do{
poly_add(&poly2);
clearEnter();
printf("Continue?(y or n)\n");
scanf("%c", &choice);
} while (choice != 'n');
printf("The poly2:\n");
poly_print(&poly2);
printf("The size of the poly2: %u\n", poly2.size);
clearEnter();
printf("What do you want to do with this two poly?\n");
choice_list();
char selection;
scanf("%c", &selection);
switch (selection) {
case 'a':
//多项式相加
poly3 = poly_combine(&poly1, &poly2);
printf("The sum of poly1 & poly2:\n");
poly_print(&poly3);
printf("The size of the poly: %u\n", poly3.size);
break;
case 'b':
//多项式相乘
poly4 = poly_multiply(&poly1, &poly2);
printf("The product of poly1 & poly2:\n");
poly_print(&poly4);
printf("The size of the poly: %u\n", poly4.size);
break;
default:
printf("No matched selection.\n");
break;
}
poly_free(&poly1);
poly_free(&poly2);
poly_free(&poly3);
poly_free(&poly4);
return 0;
}
inline
void clearEnter(void){//清空缓冲区
while (getchar() != '\n') {
continue;
}
}
void choice_list(void){
printf("(a) get sum\t\t"); printf("(b) get product\n");
}
测试结果:
求和:
预期结果:
测试:(太长一张图放不下)
结果正确