数据结构之一元多项式的加法和乘法

Polynomial.h
  1 #define _CRT_SECURE_NO_DEPRECATE
  2 #include "Polynomial.h"
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 
  6 int ListLength(NormLinkList *L)
  7 {
  8     int num = 0;
  9     Link p = NextPos(L, GetHead(L));
 10     while(p)
 11     {
 12         num++;
 13         p = NextPos(L, p);
 14     }
 15     return num;
 16 }//PolynLength()个人觉得这两个函数功能一样
 17 
 18 Status MakeNode(Link *p, ElemType e)
 19 {
 20     //分配由*p指向的值为e的节点,并返回OK;若分配失败,则返回ERROR(此处使用了指向指针的指针p,*p为节点的地址)
 21     *p = (Link)malloc(sizeof(NormLNode));
 22     if(!(*p))
 23         return ERROR;
 24     (*p)->data = e;
 25     (*p)->next = NULL;
 26     return OK;
 27 }
 28 
 29 void FreeNode(Link p)
 30 {
 31     //释放p所指节点
 32     free(p);
 33 }
 34 
 35 
 36 Status InitList(NormLinkList *L)
 37 {
 38     //构造一个空的线性链表L
 39     L->head = (Link)malloc(sizeof(NormLNode));//生成头节点
 40     if(!(L->head))
 41         return ERROR;
 42     L->head->next = NULL;
 43     L->tail = L->head;
 44     L->len = 0;
 45     return OK;
 46 }
 47 
 48 
 49 Status DestroyList(NormLinkList *L)
 50 {
 51     //销毁线性链表L,L不再存在
 52     Link p = L -> head -> next;//p指向L的第一个节点
 53     Link q;
 54     while(p)
 55     {
 56         q = p -> next;
 57         free(p);
 58         p = q;
 59     }
 60     free(L -> head);//释放头节点空间
 61     free(L);
 62     return OK;
 63 }
 64 
 65 
 66 Status ClearList(NormLinkList *L)
 67 {
 68     //将线性链表L重置为空表(仅有头节点),并释放原链表的存储空间
 69     Link p = L -> head -> next;//p指向L的第一个节点
 70     Link q;
 71     while(p)
 72     {
 73         q = p -> next;
 74         free(p);
 75         p = q;
 76     }
 77     L -> head -> next = NULL;
 78     L -> tail = L -> head;
 79     L -> len = 0;
 80     return OK;
 81 }
 82 
 83 
 84 Status InsFirst(Link h, Link s)
 85 {
 86     //将s所指节点插入在第一个节点之前
 87     if(h && s)
 88     {
 89         s -> next = h -> next;
 90         h -> next = s;
 91         return OK;
 92     }
 93     else
 94         return ERROR;
 95 }
 96 
 97 
 98 Status DelFirst(Link h, Link *q)
 99 {
100     //删除链表中的第一个节点,并用q返回
101     *q = h -> next;//*q指向待删除节点
102     h -> next = (*q) -> next;
103     (*q)->next = NULL;//非常重要,否则*q会链接到剩余的节点
104     return OK;
105 }
106 
107 
108 Status Append(NormLinkList *L, Link s)
109 {
110     //将指针s所指(彼此以指针相链接)的一串节点链接在线性链表L的最后一个节点之后,
111     //并改变链表L的尾指针指向新的尾节点
112     Link p = s, q = s;//p指向s,q保持在p前面
113     int j = 0;//指示s中的节点个数,用于更新L->len,考虑到了s为空的情况,此时while条件不满足,j为0
114     if(!UpdateTail(L))
115         return ERROR;
116     L -> tail -> next = s;
117     while(p)
118     {
119         //退出时,q指向s中最后一个节点,j为s中的节点个数
120         j++;
121         q = p;
122         p = p -> next;
123     }
124     L -> tail = q;
125     L -> len += j;
126     return OK;
127 }
128 
129 
130 Status UpdateTail(NormLinkList *L)
131 {
132     //注意L为空表的情况
133     //更新L的尾节点,并更新链表长度
134     Link p = L -> head -> next, q = L -> head -> next;//p指向链表第一个节点,q保持在p前面
135     int j = 0;//指示s中的节点个数,用于更新L->len,考虑到了s为空的情况,此时while条件不满足,j为0
136     if(!(L->head->next))//考虑L为空的情况,此时若执行后面语句,会导致L->tail指向NULL,使得Append函数的L->tail->next = s;语句访存冲突
137         return OK;
138     while(p)
139     {
140         //退出时,q指向L中最后一个节点,j为L中的节点个数(仅在L非空时有效)
141         j++;
142         q = p;
143         p = p -> next;
144     }
145     L -> tail = q;
146     L -> len = j;
147     return OK;
148 }
149 
150 
151 Position GetHead(NormLinkList *L)
152 {
153     //返回线性链表L中头节点的位置
154     return L -> head;
155 }
156 
157 
158 Position NextPos(NormLinkList *L, Link p)
159 {
160     //已知p指向线性链表L中的一个节点,返回p所指节点的直接后继的位置,若无后继,则返回NULL
161     return p->next;
162 }
163 
164 
165 ElemType GetCurElem(Link p)
166 {
167     //已知p指向线性链表中的一个节点,返回p所指节点中数据元素的值
168     return p -> data;
169 }
170 
171 
172 Status LocatePos(NormLinkList *L, int i, Link *p)
173 {
174     //用*p返回线性链表L中第i个节点的位置并返回OK,i值不合法时返回ERROR。此处p为指向指针的指针,用于返回第i个节点的地址
175     //0 <= i <= 表长;(i取0时,返回头节点位置,用于在L的第一个节点前插入元素,ListInsert_NL调用时会用到)
176     Link q = L -> head;//q指向L中的头节点
177     int j = 0;
178     while(q && j < i)
179     {
180         //退出时,q == NULL,或者j == i
181         q = q->next;
182         j++;
183     }
184     if(!q || j > i)//q为空,或者 i < 0,即第i个元素不存在
185         return ERROR;
186     *p = q;//此时q指向L中第i个节点的位置
187     return OK;
188 }
189 
190 
191 Status SetCurElem(Link p, ElemType e)
192 {
193     //已知p指向线性链表中的一个节点,用e更新p所指节点中数据元素的值
194     if(p)
195         p->data = e;
196     else
197         return ERROR;
198     return OK;
199 }
200 
201 
202 Status LocateElem(NormLinkList *L, ElemType e, Position *q, Status (* compare)(ElemType, ElemType))
203 {
204     //若有序链表L中存在与e满足判定函数compare()取值为0的元素,则*q指示L中第一个值为e的节点的位置,并返回TRUE
205     //否则*q指示第一个与e满足判定函数compare()取值>0的元素的前驱的位置,并返回FALSE。此处p为指向指针的指针,用于返回满足条件的节点的地址
206     Position p = L -> head, r = L -> head -> next;//p指向L中的头节点,r作为p的直接后继
207     while(r && (* compare)(r -> data, e) < 0)
208     {
209         //退出时,要么r为NULL,要么r->data的指数项等于或者大于e的指数项
210         p = r;
211         r = r->next;
212     }
213     if(r == NULL)
214     {
215         //要么表为空,要么e的指数项大于L中的最高指数项,此时返回r的直接前驱p
216         *q = p;
217         return FALSE;
218     }
219     else
220     {
221         //r不为空
222         if((* compare)(r->data, e) == 0)
223         {
224             //存在与e指数项相同的节点,此时r指向该节点
225             *q = r;
226             return TRUE;
227         }
228         else
229         {
230             //不存在与e指数项相同的节点,此时r->data的指数项大于e的指数项,此时返回r的直接前驱p
231             *q = p;
232             return FALSE;
233         }
234     }
235 
236 }
237 
238 
239 Status ListEmpty(NormLinkList *L)
240 {
241     //若线性链表L为空表,则返回TRUE,否则返回FALSE
242     if(L -> head -> next == NULL)
243         return TRUE;
244     else
245         return FALSE;
246 }
247 
248 
249 Status ListInsert_NL(NormLinkList *L, int i, ElemType e)
250 {
251     //在带头节点的单链线性表L的第i个元素之前插入元素e
252     Link *h = (Link *)malloc(sizeof(Link));
253     Link *s = (Link *)malloc(sizeof(Link));
254     if(!LocatePos(L, i-1, h))//i值在链表范围之外,即i<=0,或者i>表长;否则,通过*h返回L中的第i-1个节点的位置
255         return ERROR;
256     if(!MakeNode(s, e))//结点存储分配失败;否则,通过*s返回新生成的节点地址
257         return ERROR;
258     InsFirst(*h, *s);//将节点*s插入到节点*h后面
259     return OK;
260 }
261 
262 
263 Status MergeList_NL(NormLinkList *La, NormLinkList *Lb, NormLinkList *Lc, int (* compare)(ElemType, ElemType))
264 {
265     //UpdateTail函数中未处理表为空的情况
266     //已知单链线性表La和Lb的元素按值非递减排列
267     //归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列
268     Position ha = GetHead(La);
269     Position hb = GetHead(Lb);//ha,hb分别指向La,Lb的头节点
270     Position pa = NextPos(La, ha);
271     Position pb = NextPos(Lb, hb);//pa,pb分别指向La,Lb的当前节点(第一个节点)
272     ElemType a, b;
273     Link *q = (Link *)malloc(sizeof(Link));
274     while(pa && pb)
275     {
276         //pa,pb均不为空
277         a = GetCurElem(pa);
278         b = GetCurElem(pb);//a,b为两表中待比较元素
279         if((* compare)(a, b) <= 0)
280         {
281             //a <= b
282             DelFirst(ha, q);
283             Append(Lc, *q);
284             pa = NextPos(La, ha);
285         }
286         else
287         {
288             //a > b
289             DelFirst(hb, q);
290             Append(Lc,*q);
291             pb = NextPos(Lb, hb);
292         }
293     }
294     if(pa)
295         Append(Lc, pa);
296     else
297         Append(Lc, pb);
298     FreeNode(ha);
299     FreeNode(hb);
300     return OK;
301 }
302 
303 
304 int cmp(term a, term b)
305 {
306     //根据a的指数值<(或=)(或>)b的指数值,分别返回-1,0,+1
307     if(a.expn < b.expn)
308         return -1;
309     else if(a.expn == b.expn)
310         return 0;
311     else
312         return 1;
313 }
314 
315 
316 void CreatePolyn(polynomial *P, int m)
317 {
318     //输入m项的系数和指数,建立表示一元多项式的有序链表P
319     //最多能输入m项,若输入指数相同的项,则后输入项会被丢弃
320     Position h;
321     Position *q = (Position *)malloc(sizeof(Position));//指针使用前一定要先初始化
322     Position *s = (Position *)malloc(sizeof(Position));
323     term e;
324     int i;
325     InitList(P);
326     h = GetHead(P);
327     e.coef = 0.0;
328     e.expn = -1;
329     SetCurElem(h, e);
330     for(i = 1; i <= m; i++)
331     {
332         scanf("%f %d", &(e.coef), &(e.expn));
333         if(!(LocateElem(P, e, q, cmp)))
334         {
335             //当前链表不存在该指数项
336             if(MakeNode(s, e))//生成节点并插入链表
337                 InsFirst(*q, *s);
338         }
339     }
340 }
341 
342 
343 void PrintPolyn(polynomial *P)
344 {
345     //打印输出一元多项式
346     Position p = P -> head -> next;//p指向链表P的第一个节点
347     int i = 1;
348     while(p)
349     {
350         if(i != 1)
351             printf(" + ");
352         printf("%fx^%d", p->data.coef, p->data.expn);
353         p = p->next;
354         i++;
355     }
356     printf("\n\n");
357 }
358 
359 
360 void AddPolyn(polynomial *Pa, polynomial *Pb)
361 {
362     //完成多项式相加运算,即:Pa = Pa + Pb,并销毁一元多项式Pb
363     term a, b;
364     int diff;
365     float sum;
366     Position *dp = (Position *)malloc(sizeof(Position));//*dp中用于保存被删除节点的地址
367     Position ha = GetHead(Pa);
368     Position hb = GetHead(Pb);//ha,hb分别指向Pa,Pb的头节点
369     Position qa = NextPos(Pa, ha);
370     Position qb = NextPos(Pb, hb);//qa,qb分别指向Pa,Pb的当前待处理结点
371     while(qa && qb)
372     {
373         //qa与qb均为非空
374         a = GetCurElem(qa);
375         b = GetCurElem(qb);//a,b为当前待比较元素
376         diff = cmp(a, b);
377         if(diff == -1)
378         {
379             //多项式Pa中当前结点的指数值小
380             ha = qa;
381             qa = NextPos(Pa, qa);//ha指向qa,qa往后走
382         }
383         else if(diff == 0)
384         {
385             sum = a.coef + b.coef;
386             if(sum != 0.0)
387             {
388                 //修改多项式Pa中当前结点的系数值
389                 a.coef = sum;
390                 SetCurElem(qa, a);//教材此处有误,第二个参数应为term类型
391                 ha = qa;//此处为后面qa = NextPos(Pa, ha)做准备,使得当qa指向节点不被删除时,ha即相当于qa
392             }
393             else
394             {
395                 //删除多项式Pa中当前结点
396                 DelFirst(ha, dp);//此处使用dp,为了跟DelFirst的函数原型匹配,因此与教材写法不同
397                 FreeNode(*dp);//实际*dp的内容就是qa
398             }
399             DelFirst(hb,dp);//此处使用dp,为了跟DelFirst的函数原型匹配,因此与教材写法不同
400             FreeNode(*dp);//实际*dp的内容就是qb
401             qb = NextPos(Pb, hb);
402             qa = NextPos(Pa, ha);
403         }
404         else
405         {
406             //多项式Pb中当前结点的指数值小
407             DelFirst(hb, dp);//此处使用dp,为了跟DelFirst的函数原型匹配,因此与教材写法不同
408             InsFirst(ha, *dp);//将Pb的当前节点接在ha后面,实际*dp的内容就是qb
409             qb = NextPos(Pb, hb);
410             ha = NextPos(Pa, ha);//ha指向刚插入的节点,即*dp
411         }
412     }//while
413     if(!ListEmpty(Pb))
414         Append(Pa, qb);//链接Pb中剩余节点
415     FreeNode(hb);
416 }
417 
418 
419 void Multpolyn(polynomial *Pa, polynomial *Pb)
420 {
421     //实现两个一元多项式的乘法
422     float coef0 = 0.0; int expn0 = 0; ElemType a;
423     Link mid0 = NULL, mid1 = NULL, mid2 = NULL;
424     Link PaH = GetHead(Pa);
425     polynomial *pa = (polynomial *)malloc(sizeof(polynomial));
426     polynomial *Pc = (polynomial *)malloc(sizeof(polynomial));
427     polynomial *Pd = (polynomial *)malloc(sizeof(polynomial));
428 
429     PaH = NextPos(Pa, PaH);//PaH -> next
430     a = GetCurElem(PaH);//PaH->data
431     coef0 = a.coef;
432     expn0 = a.expn;
433 
434     InitList(pa); InitList(Pc); InitList(Pd);//init
435 
436     pa -> head -> data = GetCurElem(GetHead(Pa));//Pa ->head->data;
437     mid0 = NextPos(Pa, (GetHead(Pa)));//mid0 = Pa -> head->next
438     pa -> head -> next = NULL;
439     mid1 =GetHead(pa);//pa -> head;
440     while(mid0)
441     {
442         //完成Pa的copy
443         mid1 -> next = (Link)malloc(sizeof(NormLNode));
444         mid1 = NextPos(pa,mid1);//mid1 -> next,
445         mid1 ->next = NULL;
446         mid1->data = GetCurElem(mid0);
447         //mid1 -> data.coef = mid0 -> data.coef, mid1 -> data.expn = mid0 -> data.expn;
448         mid0 = NextPos(Pa, mid0);//mid0 -> next;
449     }
450     pa -> tail = mid1, pa -> len = Pa -> len;//处理pa的尾结点和长度
451 
452     mid0 = NextPos(Pa, GetHead(Pa));//Pa -> head -> next
453     while(mid0)
454     {
455         //完成Pa 与 Pb第一项相乘
456         mid0 -> data.coef = mid0 -> data.coef * coef0, mid0 -> data.expn = mid0 -> data.expn + expn0;
457         mid0 = NextPos(Pa, mid0);//mid0 -> next;
458     }
459 
460     //完成后续工作
461     //mid0 = pa -> head -> next;
462     //mid1 = Pc -> head;
463     mid2 = NextPos(Pb,NextPos(Pb,GetHead(Pb)));//Pb -> head -> next -> next;
464     while(mid2)
465     {
466         mid1 = GetHead(Pc);//Pc -> head;
467         mid0 = NextPos(pa,GetHead(pa));//pa -> head -> next;
468         while(mid0)
469         {
470             mid1 -> next = (Link)malloc(sizeof(NormLNode));
471             mid1 = NextPos(Pc, mid1);//mid1 -> next;
472             mid1 -> data.coef = mid0 -> data.coef * mid2 -> data.coef;
473             mid1 -> data.expn = mid0 -> data.expn +mid2 -> data.expn;
474             mid0 = NextPos(pa, mid0);//mid0 -> next;
475         }
476         mid1 -> next = NULL;//处理尾巴,否则Append()函数中while循环无法判定
477         Pc -> tail = mid1;
478         AddPolyn(Pa, Pc);
479         Pc = (polynomial *)malloc(sizeof(polynomial));
480         InitList(Pc);
481         mid2 = NextPos(Pb, mid2);//mid2 -> next;
482     }
483     Pa -> len = ListLength(Pa);
484 }
485 
486 
487 int main()
488 {
489 /*******************************测试一元多项式加法*******************************/
490     polynomial *Pa = (polynomial *)malloc(sizeof(polynomial));
491     polynomial *Pb = (polynomial *)malloc(sizeof(polynomial));
492     printf("分别输入一个4项的多项式和一个3项的多项式\n");
493     CreatePolyn(Pa, 4);
494     printf("Pa:\n");
495     PrintPolyn(Pa);
496     CreatePolyn(Pb, 3);
497     printf("\nPb:\n");
498     PrintPolyn(Pb);
499     AddPolyn(Pa, Pb);
500     printf("\nPa+Pb:\n");
501     PrintPolyn(Pa);
502     DestroyList(Pa);
503 /*******************************测试一元多项式乘法*******************************/
504     Pa = (polynomial *)malloc(sizeof(polynomial));
505     Pb = (polynomial *)malloc(sizeof(polynomial));
506     printf("分别输入一个4项的多项式和一个3项的多项式\n");
507     CreatePolyn(Pa, 4);
508     printf("Pa:\n");
509     PrintPolyn(Pa);
510     CreatePolyn(Pb, 3);
511     printf("\nPb:\n");
512     PrintPolyn(Pb);
513     printf("\nPa * Pb\n");
514     Multpolyn(Pa, Pb);
515     PrintPolyn(Pa);
516     DestroyList(Pa);
517 return 0;
518 }

这么多行的代码不容易啊,虽然里面还有好多函数还没有实现,等待慢慢补充吧(虽然可能性不大,过段时间估计看着都头疼了吧,还是要给自己个勇气嘛)。 

posted @ 2016-10-08 21:42  jb-simple  阅读(4846)  评论(0编辑  收藏  举报