[C数据结构与算法]链表的应用-多项式的表达与运算

文章介绍了如何使用顺序表和线性链表存储一元多项式,特别是对于指数非连续的情况。详细阐述了一元多项式加法和乘法的代码实现,包括在链表中如何合并和计算。加法通过比较和移动节点实现,乘法通过多项式单项式相乘然后求和。
摘要由CSDN通过智能技术生成

一元多项式的表达

对于形同 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++pmxem0e1<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时存在以下三种情况:

  1. A A A 节点的指数 > > > B B B节点的指数,或者节点 A A A为空: 将节点 B B B从原链表摘除插入到链表listC
  2. A A A 节点的指数 < < < B B B节点的指数,或者节点 B B B为空: 将节点 A A A从原链表摘除插入到链表listC
  3. 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=1nbiA(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=1nbiA(x)xei


Reference

文章封面来自Pixiv画师ぢせ https://www.pixiv.net/artworks/79306187

内容想法来自图书 数据结构(C语言版)-清华大学出版社

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值