1. 引言
本文主要讲解一元多项式的表示及相加。
2. 一元多项式的表示和及相加
/* 一元多项式的表示和相加 */ #include "ds.h" using namespace std; #ifdef TEST_LIST typedef int ElemType; #else typedef struct { float coef; //系数 int expn; //指数 }term, ElemType; // 两个类型名:term用于本ADT,ElemType为LinkList的数据对象名 #endif typedef struct LNode{ ElemType data; struct LNode *next; }LNode, *Link, *Position; typedef struct { Link head, tail; int len; }LinkList; #ifndef TEST_LIST typedef LinkList polynomial; #define DestroyPolyn DestroyList // 与bo2-6.cpp中的函数同义不同名 #define PolynLength ListLength // 与bo2-6.cpp中的函数同义不同名 #endif void MakeNode(Link &p, ElemType e); void FreeNode(Link &p); void InitList(LinkList &L); void ClearList(LinkList &L); void DestroyList(LinkList &L); // h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前, 形参增加L,因为需修改L void InsFirst(LinkList &L,Link h,Link s); // h指向L的一个结点,把h当做头结点,删除链表中的第一个结点并以q返回。 // 若链表为空(h指向尾结点),q=NULL,返回FALSE Status DelFirst(LinkList &L, Link h, Link &q); // 将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的 // 一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新的尾结点 void Append(LinkList &L, Link s); // 已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置。若无前驱,则返回NULL Position PriorPos(LinkList L, Link p); // 删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点 Status Remove(LinkList &L, Link &q); // 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前, // 并修改指针p指向新插入的结点 void InsBefore(LinkList &L, Link &p, Link s); // 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后, // 并修改指针p指向新插入的结点 void InsAfter(LinkList &L,Link &p,Link s); // 已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值 void SetCurElem(Link p, ElemType e); ElemType GetCurElem(Link p); Status ListEmpty(LinkList L); int ListLength(LinkList L); Position NextPos(Link p); Position GetHead(LinkList L); Position GetLast(LinkList L); // 返回p指示线性链表L中第i个结点的位置,并返回OK,i值不合法时返回ERROR。i=0为头结点 Status LocatePos(LinkList L, int i, Link &p); // 返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置, // 若不存在这样的元素,则返回NULL Position LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType)); void ListTraverse(LinkList L, void(*visit)(ElemType) ); // 已知L为有序线性链表,将元素e按非降序插入在L中。 void OrderInsert(LinkList &L, ElemType e, int (*com)(ElemType, ElemType)); // 若升序链表L中存在与e满足判定函数compare()取值为0的元素,则q指示L中 // 第一个值为e的结点的位置,并返回TRUE;否则q指示第一个与e满足判定函数 // compare()取值>0的元素的前驱的位置。并返回FALSE。(用于一元多项式) Status LocateElem(LinkList L,ElemType e,Position &q,int(*compare)(ElemType,ElemType)); void MakeNode(Link &p, ElemType e) { p = (Link)malloc(sizeof(LNode)); if (!p) exit(ERROR); memcpy(&(p->data), &e, sizeof(ElemType)); p->next = NULL; } void FreeNode(Link &p) { free(p); p = NULL; } // 带头结点的单链表 void InitList(LinkList &L) { Link p; p = (Link)malloc(sizeof(LNode)); //生成头结点 if (p) { L.head = L.tail = p; L.tail->next = NULL; L.len = 0; } else exit(ERROR); } void ClearList(LinkList &L) { Link q, p = L.head->next; if (0 == L.len) return; L.head->next = NULL; while (p) { q = p->next; free(p); p = q; } L.tail = L.head; L.len = 0; } void DestroyList(LinkList &L) { ClearList(L); FreeNode(L.head); L.tail = NULL; L.len = 0; } // h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前, 形参增加L,因为需修改L void InsFirst(LinkList &L,Link h,Link s) { s->next = h->next; h->next = s; if (h == L.tail) L.tail = h->next; L.len++; } // h指向L的一个结点,把h当做头结点,删除链表中的第一个结点并以q返回。 // 若链表为空(h指向尾结点),q=NULL,返回FALSE Status DelFirst(LinkList &L, Link h, Link &q) { #if 0 q = h->next; if (h == L.tail) return FALSE; h->next = q->next; if (!q->next) L.tail = h; L.len--; return OK; #endif q=h->next; if(q) // 链表非空 { h->next=q->next; if(!h->next) // 删除尾结点 L.tail=h; // 修改尾指针 L.len--; return OK; } else return FALSE; // 链表空 } // 将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的 // 一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新的尾结点 void Append(LinkList &L, Link s) { int i = 1; L.tail->next = s; if (NULL == s) return; while (s->next) { s = s->next; i++; } L.tail = s; L.len += i; } // 已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置。若无前驱,则返回NULL Position PriorPos(LinkList L, Link p) { Link q = L.head->next; if (!L.len || 1 == L.len) return NULL; while (q->next && q->next != p) { q = q->next; } if (!q->next) return NULL; return q; } // 删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点 Status Remove(LinkList &L, Link &q) { Link p = L.head; q = L.tail; if (!L.len) { q = NULL; return ERROR; } while (p->next != L.tail) { p = p->next; } p->next = NULL; L.tail = p; L.len--; return OK; } // 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前, // 并修改指针p指向新插入的结点 void InsBefore(LinkList &L, Link &p, Link s) { Link pp = L.head; while (pp->next && pp->next != p) pp = pp->next; if (pp->next) { s->next = pp->next; pp->next = s; } else return; p = s; L.len++; } // 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后, // 并修改指针p指向新插入的结点 void InsAfter(LinkList &L,Link &p,Link s) { if (p == L.tail) { s->next = p->next; p->next = s; L.tail = s; } else { s->next = p->next; p->next = s; } p = s; L.len++; } // 已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值 void SetCurElem(Link p, ElemType e) { memcpy(&(p->data), &e, sizeof(ElemType)); } ElemType GetCurElem(Link p) { return p->data; } Status ListEmpty(LinkList L) { if (L.len) return FALSE; else return TRUE; } int ListLength(LinkList L) { return L.len; } Position GetHead(LinkList L) { return L.head; } Position GetLast(LinkList L) { return L.tail; } Position NextPos(Link p) { return p->next; } // 返回p指示线性链表L中第i个结点的位置,并返回OK,i值不合法时返回ERROR。i=0为头结点 Status LocatePos(LinkList L, int i, Link &p) { int j = 0; if (i < 0 || i > L.len) return ERROR; p = L.head; for (; j < i; j++) p = p->next; return OK; } // 返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置, // 若不存在这样的元素,则返回NULL Position LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType)) { Link p = L.head->next; while (p && !compare(e, p->data)) p = p->next; if (!p) return NULL; return p; } void ListTraverse(LinkList L, void(*visit)(ElemType) ) { Link p = L.head->next; while (p) { visit(p->data); p = p->next; } printf("\n"); } // 已知L为有序线性链表,将元素e按非降序插入在L中。 void OrderInsert(LinkList &L, ElemType e, int (*comp)(ElemType, ElemType)) { #if 1 Link q = L.head, s; Link p = q->next; MakeNode(s, e); while (p && comp(p->data, e) < 0) // p不是表尾且元素值小于e { q = p; p = p->next; } q->next = s; s->next = p; if (!p) // 插在表尾 L.tail = s; // 修改尾结点 L.len++; #else Link o,p,q; q=L.head; p=q->next; while(p!=NULL&&comp(p->data,e)<0) // p不是表尾且元素值小于e { q=p; p=p->next; } o=(Link)malloc(sizeof(LNode)); // 生成结点 o->data=e; // 赋值 q->next=o; // 插入 o->next=p; L.len++; // 表长加1 if(!p) // 插在表尾 L.tail=o; // 修改尾结点 #endif } // 若升序链表L中存在与e满足判定函数compare()取值为0的元素,则q指示L中 // 第一个值为e的结点的位置,并返回TRUE;否则q指示第一个与e满足判定函数 // compare()取值>0的元素的前驱的位置。并返回FALSE。(用于一元多项式) Status LocateElem(LinkList L,ElemType e,Position &q,int(*compare)(ElemType,ElemType)) { Link p = L.head; do { q = p; p = p->next; }while (p && compare(p->data, e) < 0); if (p && compare(p->data, e) == 0) { q = p; return TRUE; } else { return FALSE; } } #ifdef TEST_LIST void print(ElemType e) { printf("%d ", e); } int comp(ElemType a, ElemType b) { return a-b; } Status equal(ElemType c1,ElemType c2) { // 判断是否相等的函数 if(c1==c2) return TRUE; else return FALSE; } #else void PrintPolyn(polynomial P) { // 打印输出一元多项式P Link q; q=P.head->next; // q指向第1个结点 printf(" 系数 指数\n"); while(q) { printf("%f %d\n",q->data.coef,q->data.expn); q=q->next; } } int cmp(term a,term b) // CreatPolyn()的实参 { // 依a的指数值<、=或>b的指数值,分别返回-1、0或+1 if(a.expn==b.expn) return 0; else return (a.expn-b.expn)/abs(a.expn-b.expn); } #endif void OrderInsertMerge(LinkList &L,ElemType e,int(* compare)(term,term)) { // 按有序判定函数compare()的约定,将值为e的结点插入或合并到升序链表L的适当位置 Position q,s; if(LocateElem(L,e,q,compare)) // L中存在该指数项 { q->data.coef+=e.coef; // 改变当前结点系数的值 if(!q->data.coef) // 系数为0 { // 删除多项式L中当前结点 s=PriorPos(L,q); // s为当前结点的前驱 if(!s) // q无前驱 s=L.head; DelFirst(L,s,q); FreeNode(q); } } else // 生成该指数项并插入链表 { MakeNode(s,e); // 生成结点 InsFirst(L,q,s); } } void CreatPolyn(polynomial &P,int m) // 算法2.22 { // 输入m项的系数和指数,建立表示一元多项式的有序链表P Position q,s; term e; int i; InitList(P); printf("请依次输入%d个系数,指数:\n",m); for(i=1;i<=m;++i) { // 依次输入m个非零项(可按任意顺序) scanf("%f,%d",&e.coef,&e.expn); if(!LocateElem(P,e,q,cmp)) // 当前链表中不存在该指数项,cmp是实参 { MakeNode(s,e); // 生成结点并插入链表 InsFirst(P,q,s); } } } void AddPolyn(polynomial &Pa,polynomial &Pb) // 算法2.23 { // 多项式加法:Pa=Pa+Pb,并销毁一元多项式Pb Position ha,hb,qa,qb; term a,b; ha=GetHead(Pa); hb=GetHead(Pb); // ha和hb分别指向Pa和Pb的头结点 qa=NextPos(ha); qb=NextPos(hb); // qa和qb分别指向Pa和Pb中当前结点(现为第1个结点) while(!ListEmpty(Pa)&&!ListEmpty(Pb)&&qa) { // Pa和Pb均非空且ha没指向尾结点(qa!=0) a=GetCurElem(qa); b=GetCurElem(qb); // a和b为两表中当前比较元素 switch(cmp(a,b)) { case -1:ha=qa; // 多项式Pa中当前结点的指数值小 qa=NextPos(ha); // ha和qa均向后移1个结点 break; case 0: qa->data.coef+=qb->data.coef; // 两者的指数值相等,修改Pa当前结点的系数值 if(qa->data.coef==0) // 删除多项式Pa中当前结点 { DelFirst(Pa,ha,qa); FreeNode(qa); } else ha=qa; DelFirst(Pb,hb,qb); FreeNode(qb); qb=NextPos(hb); qa=NextPos(ha); break; case 1: DelFirst(Pb,hb,qb); // 多项式Pb中当前结点的指数值小 InsFirst(Pa,ha,qb); ha=ha->next; qb=NextPos(hb); } } if(!ListEmpty(Pb)) { qa = qb; Pb.tail=hb; Append(Pa,qa); // 链接Pb中剩余结点 } DestroyPolyn(Pb); // 销毁Pb } void AddPolyn1(polynomial &Pa,polynomial &Pb) { // 另一种多项式加法的算法:Pa=Pa+Pb,并销毁一元多项式Pb Position qb; term b; qb=GetHead(Pb); // qb指向Pb的头结点 qb=qb->next; // qb指向Pb的第1个结点 while(qb) { b=GetCurElem(qb); OrderInsertMerge(Pa,b,cmp); qb=qb->next; } DestroyPolyn(Pb); // 销毁Pb } void Opposite(polynomial &Pa) { // 一元多项式Pa系数取反 Position p; p=Pa.head; while(p->next) { p=p->next; p->data.coef*=-1; } } void SubtractPolyn(polynomial &Pa,polynomial &Pb) { // 多项式减法:Pa=Pa-Pb,并销毁一元多项式Pb Opposite(Pb); AddPolyn1(Pa,Pb); } void MultiplyPolyn(polynomial &Pa,polynomial &Pb) { // 多项式乘法:Pa=Pa×Pb,并销毁一元多项式Pb polynomial Pc; Position qa,qb; term a,b,c; InitList(Pc); qa=GetHead(Pa); qa=qa->next; while(qa) { a=GetCurElem(qa); qb=GetHead(Pb); qb=qb->next; while(qb) { b=GetCurElem(qb); c.coef=a.coef*b.coef; c.expn=a.expn+b.expn; OrderInsertMerge(Pc,c,cmp); qb=qb->next; } qa=qa->next; } DestroyPolyn(Pb); // 销毁Pb ClearList(Pa); // 将Pa重置为空表 Pa.head=Pc.head; Pa.tail=Pc.tail; Pa.len=Pc.len; } #ifdef TEST_LIST int main() { Link p,h; LinkList L; Status i; int j,k; InitList(L); // 初始化空的线性表L for(j=1;j<=2;j++) { MakeNode(p,j); // 生成由p指向、值为j的结点 InsFirst(L,L.tail,p); // 插在表尾 } ListTraverse(L,print); // 输出L cout << "L'length:"<< ListLength(L) << endl; OrderInsert(L,0,comp); // 按升序插在有序表头 ListTraverse(L,print); // 输出L cout << "L'length:"<< ListLength(L) << endl; for(j=0;j<=3;j++) { i=LocateElem(L,j,p,comp); if(i) printf("链表中有值为%d的元素。\n",p->data); else printf("链表中没有值为%d的元素。\n",j); } printf("输出链表:"); ListTraverse(L,print); // 输出L cout << "L'length:"<< ListLength(L) << endl; for(j=1;j<=4;j++) { printf("删除表头结点:"); DelFirst(L,L.head,p); // 删除L的首结点,并以p返回 if(p) printf("%d\n",GetCurElem(p)); else printf("表空,无法删除 p=%u\n",p); } printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n",ListLength(L),ListEmpty(L)); MakeNode(p,10); p->next=NULL; // 尾结点 for(j=4;j>=1;j--) { MakeNode(h,j*2); h->next=p; p=h; } // h指向一串5个结点,其值依次是2 4 6 8 10 Append(L,h); // 把结点h链接在线性链表L的最后一个结点之后 OrderInsert(L,12,comp); // 按升序插在有序表尾头 OrderInsert(L,7,comp); // 按升序插在有序表中间 printf("输出链表:"); ListTraverse(L,print); // 输出L for(j=1;j<=2;j++) { p=LocateElem(L,j*5,equal); if(p) printf("L中存在值为%d的结点。\n",j*5); else printf("L中不存在值为%d的结点。\n",j*5); } for(j=1;j<=2;j++) { LocatePos(L,j,p); // p指向L的第j个结点 h=PriorPos(L,p); // h指向p的前驱 if(h) printf("%d的前驱是%d。\n",p->data,h->data); else printf("%d没前驱。\n",p->data); } k=ListLength(L); for(j=k-1;j<=k;j++) { LocatePos(L,j,p); // p指向L的第j个结点 h=NextPos(p); // h指向p的后继 if(h) printf("%d的后继是%d。\n",p->data,h->data); else printf("%d没后继。\n",p->data); } printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n",ListLength(L),ListEmpty(L)); p=GetLast(L); // p指向最后一个结点 SetCurElem(p,15); // 将最后一个结点的值变为15 printf("第1个元素为%d 最后1个元素为%d\n",GetCurElem(GetHead(L)->next),GetCurElem(p)); MakeNode(h,10); InsBefore(L,p,h); // 将10插到尾结点之前,p指向新结点 p=p->next; // p恢复为尾结点 MakeNode(h,20); InsAfter(L,p,h); // 将20插到尾结点之后 k=ListLength(L); printf("依次删除表尾结点并输出其值:"); for(j=0;j<=k;j++) if(!(i=Remove(L,p))) // 删除不成功 printf("删除不成功 p=%u\n",p); else printf("%d ",p->data); MakeNode(p,29); // 重建具有1个结点(29)的链表 InsFirst(L,L.head,p); DestroyList(L); // 销毁线性链表L printf("销毁线性链表L之后: L.head=%u L.tail=%u L.len=%d\n",L.head,L.tail,L.len); } #else int main() { polynomial p,q; int m; printf("请输入第1个一元多项式的非零项的个数:"); scanf("%d",&m); CreatPolyn(p,m); printf("请输入第2个一元多项式的非零项的个数:"); scanf("%d",&m); CreatPolyn(q,m); AddPolyn(p,q); //SubtractPolyn(p,q); printf("2个一元多项式相加的结果:\n"); PrintPolyn(p); printf("请输入第3个一元多项式的非零项的个数:"); scanf("%d",&m); CreatPolyn(q,m); AddPolyn1(p,q); printf("2个一元多项式相加的结果(另一种方法):\n"); PrintPolyn(p); printf("请输入第4个一元多项式的非零项的个数:"); scanf("%d",&m); CreatPolyn(q,m); SubtractPolyn(p,q); printf("2个一元多项式相减的结果:\n"); PrintPolyn(p); printf("请输入第5个一元多项式的非零项的个数:"); scanf("%d",&m); CreatPolyn(q,m); MultiplyPolyn(p,q); printf("2个一元多项式相乘的结果:\n"); PrintPolyn(p); DestroyPolyn(p); } #endif