一元多项式的表达
对于形同 k 1 + k 2 x + k 3 x 2 + ⋯ + k n + 1 x n k_1+k_2x+k_3x^2+\cdots+k_{n+1}x^n k1+k2x+k3x2+⋯+kn+1xn 的一元多项式可以直接用顺序表存储对应位上的系数,
如: 2 + x + 3 x 2 + 2 x 3 2+x+3x^2+2x^3 2+x+3x2+2x3 在顺序表中的内存如下
但是对于 1 + x 100 + x 10000 1+x^{100}+x^{10000} 1+x100+x10000 等指数非连续的多项式,使用顺序表存储会造成大量的内存浪费. 因此对于 p 1 x e 1 + p 2 x e 2 + ⋯ + p m x e m 0 ≤ e 1 < e 2 < ⋯ < e m p_1x^{e_1}+p_2x^{e_2}+\cdots+p_mx^{e_m} \quad 0\leq e_1<e_2<\cdots<e_m p1xe1+p2xe2+⋯+pmxem0≤e1<e2<⋯<em这类多项式我们使用线性链表来储存
如: 1 + x 3 + 2 x 5 + x 7 1+x^3+2x^{5}+x^7 1+x3+2x5+x7 在链表中的内存如下
该链表的数据域存在两个属性,系数 P m P_m Pm和指数 e m e_m em,创建该链表时可能会存在头节点(该图未给出)
因此链表的结构体应为:
typedef struct PolynomialNode{
struct PolynomialNode *next;
int idx, coef; //系数Coefficient 指数Index
}PNode;
一元多项式的加法
实现该功能的逻辑是: 创建两个零时指针ptrA,ptrB
, 指针一直指向首元节点
A
,
B
A,B
A,B, 同时创建链表头指针listC
用于存储两项多项式的和,在比较节点
A
,
B
A,B
A,B时存在以下三种情况:
-
A
A
A 节点的指数
>
>
>
B
B
B节点的指数,或者节点
A
A
A为空: 将节点
B
B
B从原链表摘除插入到链表
listC
-
A
A
A 节点的指数
<
<
<
B
B
B节点的指数,或者节点
B
B
B为空: 将节点
A
A
A从原链表摘除插入到链表
listC
- 若
A
A
A节点的指数与
B
B
B节点相同: 若节点
A
,
B
A,B
A,B的系数和为
0
0
0,则仅用摘除
A
,
B
A,B
A,B节点,若不为
0
0
0,则还要插入新节点
C
C
C到链表
listC
,其指数与 A , B A,B A,B节点相同,系数为其之和
-
代码实现
PNode* addPolyn(PNode* listA,PNode* listB){ //Create list C for storing answer PNode* listC= (PNode*)malloc(sizeof(PNode)); if(!listC) return NULL; //Memory overflow listC->next= NULL; //Create tmp pointer(point to second node for AB) PNode* ptrA= listA->next; PNode* ptrB= listB->next; PNode* ptrC= listC; while(ptrA!=NULL || ptrB!=NULL){ if(ptrA==NULL || ptrA->idx>ptrB->idx){ //Insert Node B to list C ptrC->next= ptrB; //Cut off connect listB->next= ptrB->next; ptrB->next= NULL; //Move ptrB and ptrC ptrB= listB->next; ptrC= ptrC->next; } else if(ptrB==NULL || ptrA->idx<ptrB->idx){ //Insert Node A to list C ptrC->next= ptrA; //Cut off connect listA->next= ptrA->next; ptrA->next= NULL; //Move ptrA and ptrC ptrA= listA->next; ptrC= ptrC->next; } else{ if(ptrA->coef+ptrB->coef!=0){ //Create node C PNode* insNode= (PNode*)malloc(sizeof(PNode)); insNode->next= NULL; insNode->coef= ptrA->coef+ptrB->coef; insNode->idx= ptrA->idx; //Insert node C ptrC->next= insNode; ptrC= ptrC->next; } //Remove node AB listA->next= ptrA->next; ptrA->next= NULL; ptrA= listA->next; listB->next= ptrB->next; ptrB->next= NULL; ptrB= listB->next; } // printf("%dX^{%d}+",ptrC->coef,ptrC->idx); //Debug } return listC; }
在
while
循环内的条件判断ptrA==NULL || ptrA->idx>ptrB->idx
以及ptrB==NULL || ptrA->idx<ptrB->idx
条件判断的循序不能更改,因为参数若存在只有头节点的空链表时会访问不存在的idx
的属性,造成访问错误. 这是C语言的特性,若存在或运算符的判断框满足第一个条件便不去判断下一个条件了
一元多项式的乘法
对于多项式
A
(
x
)
,
B
(
x
)
A(x),B(x)
A(x),B(x),其乘法可分解为多个加法:
A
(
x
)
×
B
(
x
)
=
A
(
x
)
×
(
b
1
x
e
1
+
⋯
+
b
n
x
e
n
)
=
∑
i
=
1
n
b
i
A
(
x
)
x
e
i
A(x)\times B(x)=A(x)\times (b_1x^{e_1}+\cdots+b_nx^{e_n})=\displaystyle \sum_{i=1}^n b_iA(x)x^{e_i}
A(x)×B(x)=A(x)×(b1xe1+⋯+bnxen)=i=1∑nbiA(x)xei
因此我们只需要遍历
B
(
x
)
B(x)
B(x)中的单项式
b
i
x
e
i
b_ix^{e_i}
bixei并计算其与多项式
A
(
x
)
A(x)
A(x)的积,并使用刚才实现的多项式加法便可化积为和
至于如何计算一元多项式 A ( x ) A(x) A(x)与 b i x e i b_ix^{e_i} bixei的乘法,只需要遍历链表 A ( x ) A(x) A(x)并使与 b i x e i b_ix^{e_i} bixei系数相乘,指数相加即可
-
代码实现
PNode* mulPolyn(PNode* listA,PNode* listB){ //Create list D for storing A(x) x B(x) PNode* listD= (PNode*)malloc(sizeof(PNode)); if(!listD) return NULL; //Memory overflow listD->next= NULL; //Create list C for storing b_ix^{e_i} x A(x) PNode* listC= (PNode*)malloc(sizeof(PNode)); if(!listC) return NULL; //Memory overflow listC->next= NULL; //Create tmp pointer PNode* ptrA= listA->next; PNode* ptrB= listB->next; PNode* ptrC= listC; //Foreach list B(A is also ok) while(ptrB!=NULL){ ptrC= listC; //Recycle using list C ptrA= listA->next; //Foreach list A(B is also ok) while(ptrA!=NULL){ //Insert new node to list C PNode* insNode= (PNode*)malloc(sizeof(PNode*)); insNode->next= NULL; insNode->coef= (ptrA->coef)*(ptrB->coef); insNode->idx= ptrA->idx+ptrB->idx; ptrC->next= insNode; //Move ptr ptrA= ptrA->next; ptrC= ptrC->next; // printf("Idx: %d Coef: %d\n",insNode->idx,insNode->coef); //Debug } //Add list C to list D listD= addPolyn(listD,listC); //This will wipe out data on list C //Move ptr ptrB= ptrB->next; } return listD; }
注意所创建的链表
listC
用于存储 b i x e i × A ( x ) b_ix^{e_i} \times A(x) bixei×A(x) 的值,需要重复使用,而addPolyn
方法可以清空listC
除头节点外的所有节点.listD
用于储存 ∑ i = 1 n b i A ( x ) x e i \displaystyle \sum_{i=1}^n b_iA(x)x^{e_i} i=1∑nbiA(x)xei
Reference
文章封面来自Pixiv画师ぢせ https://www.pixiv.net/artworks/79306187
内容想法来自图书 数据结构(C语言版)-清华大学出版社