- 数据结构(C语言版)
- 邓文华主编
- 948字
- 2020-08-28 01:27:57
2.4 典型例题
一元多项式的操作已经成为表处理的典型用例。在数学上,一元多项式可按升幂的形式写成:
Pn(x)=p0+p1 x1+p2 x2+…+pn xn
式中,pi是xi项的系数,则一个最高幂次为n的多项式可由n+1个系数唯一确定,因此,在计算机里,它可以用一个线性表P来表示:
P=(p0, p1, p2, …, pn)
假设Qm(x)是一个一元多项式,同样可以用线性表Q表示:
Q=(q0, q1, q2, …, qm)
若设m<n,则两个多项式相加的结果Rn(x)= Pn(x)+Qm(x),用线性表R表示:
R=(p0 +q0, p1+q1, p2+q2, …, pm+qm, pn+1, …, pn)
显然,表示多项式的线性表可以用顺序存储结构,也可以用链式存储结构。
1.一元多项式的存储表示
(1)一元多项式的顺序存储表示。一元多项式Pn(x)的顺序存储表示有两种方法。
一种方法是:只存储多项式的各项系数(不管系数是否为零,全部按幂次的顺序存储),每个系数对应的指数隐含在存储系数的下标里。如上所述,p[0]存系数p0,对应x0的系数,p[1]存系数p1,对应x1的系数,…,p[n]存系数pn,对应xn的系数。至此,一元多项式的相加运算就非常简单,只需要将下标相同的单元内容相加即可。
然而,在通常的应用中,多项式的幂次可能很高而且变化较大,同时非零项又往往很少。例如S(x)=1+5x1000+3x20000,若采用以上方法存储,则需要20001个存储空间,而实际有用的数据只有3个,无疑是一种浪费。
另一种方法是:采取只存储非零项的方法,此时每个存储单元需要存储:非零项系数和非零项指数。即对一元多项式Pn(x),可写成:
其中,pi是指数为ei的项的非零系数,且满足
0≤e1<e2<…<em=n
则只需要存储如下线性表:
((p1, e1),(p2, e2), …, (pm, em))
便可唯一确定多项式Pn(x)。即使在最坏情况下,n+1个系数都不为零,也只比前一种方法多存储一倍的数据,但是,对于通常情况如S(x)类的多项式,这种方法将大大节省存储空间。
(2)一元多项式的链式存储表示。在链式存储中,对一元多项式只存储非零项,则作为链式存储结构的基本单元结点由三部分构成:系数、指数及指向下一结点的指针。
表示一元多项式的单链表定义如下:
struct Polynode { int coef ; /*系数*/ int eap ; /*指数*/ Polynode *next ; } PolyNode, *PolyList ;
根据以上数据类型定义,可以设计一元多项式的链表建立算法。
假设通过键盘输入一组多项式的系数和指数,用表尾插入法建立一元多项式链表,以输入系数0为输入结束标志,并规定输入多项式数据时,总是按指数从小到大的顺序输入。
算法2.19 一元多项式链表的建立算法。
PolyList polycreate ( ) { PolyNode *head, *rear, *s ; int c, e ; head=(PolyList) malloc (sizeof ( PolyNode )); /*建立头结点*/ rear=head; /*rear始终指向表尾,便于在表尾插入新结点*/ scanf ( "%d, %d", &c, &e ) ; /*输入多项式的系数和指数*/ while ( c != 0 ) /*若c=0,则表示多项式输入结束*/ { s=(PloyList ) malloc (sizeof ( PolyNode )) ; /*申请新的结点空间*/ s ->coef=c ; s ->exp=e ; rear ->next=s ; /*在当前表尾插入*/ rear=s ; scanf ( "%d, %d", &c, &e ) ; } rear ->next=NULL ; /*将表的最后一个结点的next指针置空,以示表结束*/ return ( head ) ; }
根据以上一元多项式的链式存储结构的定义,以及多项式链表的构造算法,则两个多项式A(x)= 5+4x2+7x5+8x12和B(x)= 3x+2x2-7x5的单链表表示如图2.24所示。
图2.24 多项式的单链表表示
2.一元多项式的相加运算
根据一元多项式相加的运算规则:
(1)对于两个一元多项式中所有指数相同的项,对应系数相加,若和不为零,则构成“和多项式”中的一项;
(2)对于两个一元多项式中指数不相同的项,则分别复抄到“和多项式”中去。
假设以单链表A和B分别表示两个一元多项式,则它们的和实质上就是两个链表的合并操作,而合并的具体要求必须满足以上多项式运算的两条规则。图2.25所示为图2.24中两个多项式相加的结果,其中孤立的结点为相加过程中被释放的结点。
图2.25 多项式相加得到的和多项式
显然,相加后原来的两个多项式链表已不复存在,而“和多项式”中的结点也无须另外申请空间。当然,假如需要保存原来的两个多项式链表,则相加运算就必须另外为“和多项式”申请结点空间,实现的过程大致相同。
算法2.20 一元多项式相加的算法(原多项式指数从低到高,和的指数由高到低)。
void AddPolyn ( PolyList polya, PolyList polyb ) /*将两个多项式相加,然后将和多项式存放到多项式polya中,并释放多余结点*/ { PolyList *p , *q , *tail , *s ; int sum; p=polya->next ; q=polyb->next ; /*令p, q分别指向两个链表的第一个结点*/ tail=polya ; /*tail指向和多项式链表的尾结点*/ while ( p!=NULL && q!=NULL ) { if ( p->exp<q->exp ) /*p所指当前结点的指数小,将该结点插入和多项式*/ { tail->next=p ; tail=p ; p=p->next ; } else if ( p->exp > q ->exp ) /* q所指当前结点的指数小,将之插入和多项式*/ { tail->next=q ; tail=q ; q=q ->next ; } else /*p与q所指结点的指数相同,则系数相加*/ { sum=p->coef+q ->coef ; if ( sum !=0 ) /*和不为0,则将系数修改,并插入和多项式链表*/ { p ->coef=sum ; tail->next=p ; tail=p ; p=p->next ; s=q ; q=q->next ; free ( s ) ; /*释放多余空间*/ } else /*和为0,则删除p与q所指当前结点,并将p、q指针下移*/ { s=p ; p=p->next ; free( s ) ; s=q ; q=q->next ; free ( s ) ; } } } }