链表实现多项式加减法(多项式篇)
链表是一种可以动态增删的简单数据结构,相比于长度固定的数组,链表更加灵活。利用这些特性,我们可以使用链表存储多项式,并实现多项式的加减法。
源代码
程序功能
- 从用户的输入中获取多项式。
- 将多项式中的每一项按照指数从大到小的顺序排好。
- 获取一个值,代入多项式中,计算结果并输出。
- 计算两个多项式相加和相减后的结果(合并同类项)并输出。
分析与设计
本项目中有三个模块(头文件)。
gc.h:垃圾回收器list.h:链表polynomial.h:多项式
各个头文件中声明的函数在相同名字的 .c 文件中存在对应实现。
多项式
类型
-
Term:项coef表示项的系数,exp表示项的指数,方便起见,他们的类型均为int。 -
Node、List:节点、链表list.h中这两个类型的前向声明,这样做而不引用list.h可以解决头文件循环引用的问题(list.h中引用了polynomial.h)。
函数
-
getPolynomial:获取多项式从
stdin中获取多项式,第一行为多项式的项数terms,下面terms行为多项式的值。把获取到的每一项的系数和指数存入新创建的TERM类型的节点中,如果系数不为 0,就将该节点添加到链表末尾。 -
cmpExp:指数比较当
a的指数大于b的指数时返回true,否则返回false。该函数被list.h的排序函数sortList使用。 -
printPolynomial:输出多项式当链表存在(多项式不为 0)时输出多项式,否则直接输出
0。多项式的第一项前无正负号,其余项有正负号(加减号)。 -
printCoef:输出系数系数为 1 时不输出。
-
printExp:输出指数指数为 0 时不输出;指数为 1 时只输出
x。 -
calcPolynomial:计算多项式将数代入多项式中算出具体值。
编程规范性提示:当存在缩窄的隐式类型转换应显式使用强制类型转换。如此处
pow的返回值为double类型,但在进行乘法运算时会被隐式转换为int类型,这时最好通过(int)进行显式转换。在期望表达式的地方填写(赋值)语句时最好在语句外再加一层括号。如此处
do-while的条件内正常应填写表达式,但此处为了简化代码而在其中填写了语句(不推荐该写法),此时就应该在语句外再加一层括号,便于和正常的表达式进行区分。(尤其是为了区分=和==,人们经常会把==写成=,很多编译器和 IDE 都会检查出这种错误并进行提示,但如果本意就是使用=,加上括号后就会消除提示。) -
addPolynomial:多项式相加为防止破坏原多项式,所以先将其进行复制。将复制好的两个多项式
pClone和qClone按照指数从大到小的顺序合并为一个多项式mergedList,合并的前提是两个多项式本身有序。对多项式合并同类项,消除计算后产生的 0 项(如),最后返回多项式。 -
subPolynomial:多项式相减减法与加法类似,只不过在合并多项式之前先将后一个多项式
qClone的所有系数取反。 -
combineLikeTerms:合并同类项以多项式中一项为基准,向后寻找和该项指数 n 相同的项,并把这些项加到基准项中,直到指数为 n 的项只剩一个,然后以下一项为基准项,重复上述动作。
while 基准项存在 && 下一项存在 if 基准项.指数 == 下一项.指数 基准项.系数 += 下一项.系数 下一项 = 下一项.下一项 else 基准项 = 下一项所谓「基准项」和「下一项」是动态变换的,起初代表第一项和第二项,但随着代码的执行,他们会向后移动。
为什么要在
while中添加下一项存在的条件?因为下一项 = 下一项.下一项,不加入判断在循环时会超出链表范围。 -
removeZeroTerms:移除 0 项这个函数不会改变多项式的值,但可以优化多项式的输出。由于需要改变链表类型变量本身,所以使用了指针传递。该算法的思路是先将多项式前面的 0 删去,再将其余的 0 删去。(如
,先删 x 前面的 0,再删 x 后面的 0。)其中后一段算法和 combineLikeTerms的思路相似,都存在一个基准项。两段删 0 的原因是如果不先把前面的 0 删干净就会遗留 0。while 基准项存在 if 基准项.系数 == 0 if 下一项存在 基准项 = 下一项 else 基准项 = NULL return else break while 基准项存在 && 下一项存在 if 下一项.系数 == 0 下一项 = 下一项.下一项 else 基准项 = 下一项为什么需要
Node *tmp = listPtr->head;?由于是指针传递,如果直接进行遍历会破坏原链表,所以需要复制一份。
更多内容请期待《链表实现多项式加减法(链表篇)》。