之前我们做了线性表的工具库,现在我们来利用这个工具库实现多项式的求和。
多项式求和:
例如 3.1564x^12 - 4.555687x^10 + …… = ……
这便是我们这个代码要解决的问题。
之前我们在userType.h头文件里定义了USER_TYPE类型,我们需要将int类型改变,以实现我们求和的功能。
多项式的每一项分成两个部分,系数和指数,像上面的例子,系数可以是个小数可以是个整数,可以有很多位,我们将其定义成double类型的,系数我们将其定义成整数类型。所以我们需要一个结构体。
以下为userType.h头文件里的代码:
#ifndef _USER_TYPE_H_
#define _USER_TYPE_H_
//用户在此可以更改需要的数据类型
typedef struct POLYNOMIAL {
double coefficient; //系数
int exponent; //指数
}POLY_ITEM, USER_TYPE;
#endif
我们定义了一个结构体,用来定义多项式中的一项,为增加程序的可读性,我们将该类型同时定义为POLY_ITEM类型,代表一项多项式。
第一个要考虑的问题,仍然是初始化以及销毁。因为有工具库,所以我们很多函数不需要再去写。以下为初始化和销毁的函数:
boolean initPolynomial(POLYNOMIAL **head, int capacity) {
initLinear(head, capacity);
}
void destoryPolynomial(POLYNOMIAL **head) {
destoryLinear(head);
}
我们在polynomial.h的头文件中,同意为增加程序的可读性,将LINEAR类型同时定义为POLYNOMIAL类型。以下为polynomial.h中的代码:
#ifndef _TYZ_POLYNOMIAL_H_
#define _TYZ_POLYNOMIAL_H_
#include "linear.h"
#include "userType.h"
#include "tyz.h"
typedef LINEAR POLYNOMIAL;
boolean initPolynomial(POLYNOMIAL **head, int capacity);
void destoryPolynomial(POLYNOMIAL **head);
#endif
完成了基本的函数,我们接下来就要开始从最主要的地方入手。要得到两个多项式的和,我们首先需要录入。因此,我们先编写录入函数。
以下为录入函数的代码:
boolean enterPolynomial(POLYNOMIAL *head) {
double coefficient;
int exponent;
int count = getCount(head);
POLY_ITEM item;
if (NULL == head) {
return FALSE;
}
if (count > 0) {
printf("录入功能只能对空多项式进行^_^\n");
return FALSE;
}
printf("请按幂指数降序录入多项式^>^\n");
printf("请输入系数和幂指数(当系数为0时,停止录入):\n");
scanf("%lf %d",&coefficient,&exponent);
while (fabs(coefficient) > 1e-6 && !isLinearFull(head)) {
item.coefficient = coefficient;
item.exponent = exponent;
appendElement(head, item);
printf("请输入系数和幂指数(当系数为0时,停止录入):\n");
scanf("%lf %d",&coefficient,&exponent);
}
return TRUE;
}
用户的录入规则是:按幂指数降序录入,既符合我们一般写多项式的原则,也为我们之后的求和带来方便,我们约定,只要用户输入的系数不为零,就可以一直录入,直到线性表的空间满了为止,这也是为用户的考虑,让用户不用一开始就想要录入几个多项式,我们给他方便,只要他想停止录入,输入0即可。
录入完成,我们需要完成显示的函数。先将任务拆解,要显示整个多项式,我们先显示其中一项多项式,这样编写就简单的多了。
我们回到之前的那个多项式的例子
3.1564x^12 - 4.555687x^10 + …… = ……
我们想要输出的每一项由它的正负号、系数、x、^、指数构成。并且如果这一项是第一项且它的系数是正数,则不用输出它的正号。
所以我们加入了一个参数,isFirst,将其是否是第一项的判断加入进去,以决定是不是要输出‘+’。
另外要考虑的是,该项的指数为多少,如果指数是0,则不论x为多少其值都为1,故不用输出x,如果指数为1,则不用输出指数。
按这个方法考虑,就能输出符合人日常习惯的多项式了。
以下为显示一项多项式的函数:
void showPolyItem(POLY_ITEM item, boolean isFirst) {
if (!isFirst && item.coefficient > 1e-6) {
printf("+");
}
printf("%.2lf", item.coefficient);
if (item.exponent != 0) {
printf("x");
}
if (item.exponent != 0 && item.exponent != 1) {
printf("^%d", item.exponent);
}
}
输出一项的函数做完,输出整个多项式的函数就很简单了,只需要把输出单项的函数放入循环里就可以了。
以下为输出整个多项式的函数:
void showPolynomial(const POLYNOMIAL *head) {
int index;
int count = getCount(head);
POLY_ITEM item;
for (index = 0; index < count; index++) {
getElement(head, index, &item);
showPolyItem(item, i == 0);
}
printf("\n");
}
这里面用到的好几个函数都是之前工具库里的,所以十分方便,在用showPolyItem函数时,我们传递一个实参i == 0,当i != 0时,即不是第一个,该式子值为0,传递给形参isFirst为0,通过这样形参与实参的传递,实现判断该式子是否是第一个的要求。
接下来,就是将两个多项式相加了。
我们先回想以下我们是如何做多项式相加的。比如有两个式子
a = 3x^4 + 45x^3 + 22x^2
b = 6x^4 - 33x^3 - 18x
则 a + b = (3+6)x^4 + (45-33)x^3 + 22x^2 - 18x
= 9x^4 + 12x^3 + 22x^2 - 18x
这个过程其实和编写代码是一样的,编程即把我们的手工过程用机器指令实现。
我们先比较了两个式子的指数,如果指数相等,则将两个式子的系数相加,如果两个式子不相等,则先比较后面的,最后将没有同类项的式子放在最后。我这个只是个简单的例子,如果大家多写几遍,就会发现我们所做的合并同类项,也是按照一步一步的步骤做完的,这个步骤就是程序。
以下为相加的函数代码
POLYNOMIAL *addPolynomial(const POLYNOMIAL *polyOne, const POLYNOMIAL *polyAnother) {
int polyOneIndex = 0;
int polyAnotherIndex = 0;
int polyOneCount = getCount(polyOne);
int polyAnotherCount = getCount(polyAnother);
double newCoefficient;
POLY_ITEM polyOneItem;
POLY_ITEM polyAnotherItem;
POLYNOMIAL *result = NULL;
initPolynomial(&result, getCapacity(polyOne) + getCapacity(polyAnother));
getElement(polyOne, polyOneIndex, &polyOneItem);
getElement(polyAnother, polyAnotherIndex, &polyAnotherItem);
while (polyOneIndex < polyOneCount && polyAnotherIndex < polyAnotherCount) {
if (polyOneItem.exponent > polyAnotherItem.exponent) {
appendElement(result, polyOneItem);
getElement(polyOne, ++polyOneIndex, &polyOneItem);
continue;
}
if (polyOneItem.exponent < polyAnotherItem.exponent) {
appendElement(result, polyAnotherItem);
getElement(polyAnother, ++polyAnotherIndex, &polyAnotherItem);
continue;
}
newCoefficient = polyOneItem.coefficient + polyAnotherItem.coefficient;
if (fabs(newCoefficient) > 1e-6) {
polyOneItem.coefficient = newCoefficient;
appendElement(result, polyOneItem);
}
getElement(polyOne, polyOneIndex, &polyOneItem);
getElement(polyAnother, polyAnotherIndex, &polyAnotherItem);
}
while (polyOneIndex < polyOneCount) {
appendElement(result, polyOneItem);
getElement(polyOne, ++polyOneIndex, &polyOneItem);
}
while (polyAnotherIndex < polyAnotherCount) {
appendElement(result, polyAnotherItem);
getElement(polyAnother, ++polyAnotherIndex, &polyAnotherItem);
}
return result;
}
这个函数的返回值类型为POLYNOMIAL *, 即我们将结果可以放在一个指向POLYNOMIAL类型的指针里。
按照我们的手工过程,我们先比较两个式子的指数,如果第一个大,就将第一个式子先放到结果里,小的那个之后再处理,第二个大亦然。如果都不是,那两个式子的指数一定是相等的,所以我们将其相加,生成一个newCoefficient,如果不为0,则把第一个式子的系数变为这个新系数,放进结果里。
第一轮循环完成,我们将同类项合并完成,并将两个式子中指数大的那个式子处理完成,还剩的就是两个多项式里第一次比较中较小系数的式子,因此我们再用两个循环,将剩下的式子放进结果里。
以上就是线性表的应用,工具库的创建对未来的很多程序构建都会有重大作用,就好像面向对象的语言如Python,Java等等,Python其实就是用C语言编写的,其用的很多封装的函数,也是像这样一样编写出来的。掌握工具库的创建,对理解编程会很有帮助。
完整代码如下:
polynomial.h
#ifndef _TYZ_POLYNOMIAL_H_
#define _TYZ_POLYNOMIAL_H_
#include "linear.h"
#include "userType.h"
#include "tyz.h"
typedef LINEAR POLYNOMIAL;
boolean initPolynomial(POLYNOMIAL **head, int capacity);
void destoryPolynomial(POLYNOMIAL **head);
boolean enterPolynomial(POLYNOMIAL *head);
void showPolyItem(POLY_ITEM item, boolean isFirst);
void showPolynomial(const POLYNOMIAL *head);
POLYNOMIAL *addPolynomial(const POLYNOMIAL *polyOne, const POLYNOMIAL *polyAnother);
#endif
polynomial.c
#include <stdio.h>
#include <malloc.h>
#include <math.h>
#include "polynomial.h"
#include "tyz.h"
#include "linear.h"
boolean initPolynomial(POLYNOMIAL **head, int capacity) {
return initLinear(head, capacity);
}
void destoryPolynomial(POLYNOMIAL **head) {
destoryLinear(head);
}
boolean enterPolynomial(POLYNOMIAL *head) {
double coefficient;
int exponent;
int count = getCount(head);
POLY_ITEM item;
if (NULL == head) {
return FALSE;
}
if (count > 0) {
printf("录入功能只能对空多项式进行^_^\n");
return FALSE;
}
printf("请按幂指数降序录入多项式^>^\n");
printf("请输入系数和幂指数(当系数为0时,停止录入):\n");
scanf("%lf %d",&coefficient,&exponent);
while (fabs(coefficient) > 1e-6 && !isLinearFull(head)) {
item.coefficient = coefficient;
item.exponent = exponent;
appendElement(head, item);
printf("请输入系数和幂指数(当系数为0时,停止录入):\n");
scanf("%lf %d",&coefficient,&exponent);
}
return TRUE;
}
void showPolyItem(POLY_ITEM item, boolean isFirst) {
if (!isFirst && item.coefficient > 1e-6) {
printf("+");
}
printf("%.2lf", item.coefficient);
if (item.exponent != 0) {
printf("x");
}
if (item.exponent != 0 && item.exponent != 1) {
printf("^%d", item.exponent);
}
}
void showPolynomial(const POLYNOMIAL *head) {
int index;
int count = getCount(head);
POLY_ITEM item;
for (index = 0; index < count; index++) {
getElement(head, index, &item);
showPolyItem(item, index == 0);
}
printf("\n");
}
POLYNOMIAL *addPolynomial(const POLYNOMIAL *polyOne, const POLYNOMIAL *polyAnother) {
int polyOneIndex = 0;
int polyAnotherIndex = 0;
int polyOneCount = getCount(polyOne);
int polyAnotherCount = getCount(polyAnother);
double newCoefficient;
POLY_ITEM polyOneItem;
POLY_ITEM polyAnotherItem;
POLYNOMIAL *result = NULL;
initPolynomial(&result, getCapacity(polyOne) + getCapacity(polyAnother));
getElement(polyOne, polyOneIndex, &polyOneItem);
getElement(polyAnother, polyAnotherIndex, &polyAnotherItem);
while (polyOneIndex < polyOneCount && polyAnotherIndex < polyAnotherCount) {
if (polyOneItem.exponent > polyAnotherItem.exponent) {
appendElement(result, polyOneItem);
getElement(polyOne, ++polyOneIndex, &polyOneItem);
continue;
}
if (polyOneItem.exponent < polyAnotherItem.exponent) {
appendElement(result, polyAnotherItem);
getElement(polyAnother, ++polyAnotherIndex, &polyAnotherItem);
continue;
}
newCoefficient = polyOneItem.coefficient + polyAnotherItem.coefficient;
if (fabs(newCoefficient) > 1e-6) {
polyOneItem.coefficient = newCoefficient;
appendElement(result, polyOneItem);
}
getElement(polyOne, polyOneIndex, &polyOneItem);
getElement(polyAnother, polyAnotherIndex, &polyAnotherItem);
}
while (polyOneIndex < polyOneCount) {
appendElement(result, polyOneItem);
getElement(polyOne, ++polyOneIndex, &polyOneItem);
}
while (polyAnotherIndex < polyAnotherCount) {
appendElement(result, polyAnotherItem);
getElement(polyAnother, ++polyAnotherIndex, &polyAnotherItem);
}
return result;
}
linear.h
#ifndef _TYZ_LINEAR_H_
#define _TYZ_LINEAR_H_
#include "tyz.h"
#include "userType.h"
typedef struct LINEAR {
USER_TYPE *data;
int capacity;
int count;
}LINEAR;
boolean initLinear(LINEAR **head, int capacity);
void destoryLinear(LINEAR **head);
int getCapacity(const LINEAR *head);
int getCount(const LINEAR *head);
boolean isLinearFull(const LINEAR *head);
boolean isLinearEmpty(const LINEAR *head);
boolean setElementAt(LINEAR *head, int index, USER_TYPE data);
boolean getElement(const LINEAR *head, int index, USER_TYPE *data);
boolean insertElementAt(LINEAR *head, int index, USER_TYPE data);
boolean appendElement(LINEAR *head, USER_TYPE data);
boolean removeElement(LINEAR *head, int index, USER_TYPE *data);
void clearLinear(LINEAR *head);
#endif
linear.c
#include <stdio.h>
#include <malloc.h>
#include "userType.h"
#include "tyz.h"
#include "linear.h"
boolean initLinear(LINEAR **head, int capacity) {
if (NULL != *head) {
return FALSE;
}
*head = (LINEAR *) calloc(sizeof(LINEAR),1);
(*head)->capacity = capacity;
(*head)->count = 0;
(*head)->data = (USER_TYPE *) calloc(sizeof(USER_TYPE),capacity);
return TRUE;
}
void destoryLinear(LINEAR **head) {
if (NULL == head || NULL == *head) {
return;
}
free((*head)->data);
free(*head);
*head = NULL;
}
int getCapacity(const LINEAR *head) {
return head->capacity;
}
int getCount(const LINEAR *head) {
return head->count;
}
boolean isLinearFull(const LINEAR *head) {
return head->count >= head->capacity;
}
boolean isLinearEmpty(const LINEAR *head) {
return head->count <= 0;
}
boolean setElementAt(LINEAR *head, int index, USER_TYPE data) {
if (NULL == head || index < 0 || index >= head->count) {
return FALSE;
}
head->data[index] = data;
return TRUE;
}
boolean getElement(const LINEAR *head, int index, USER_TYPE *data) {
if (NULL == head || index < 0 || index >= head->count) {
return FALSE;
}
*data = head->data[index];
return TRUE;
}
boolean insertElementAt(LINEAR *head, int index, USER_TYPE data) {
int i;
if (NULL == head || isLinearFull(head)
|| index < 0 || index >= head->count) {
return FALSE;
}
for (i = head->count; i > index; i--) {
head->data[i] = head->data[i - 1];
}
head->data[index] = data;
++head->count;
return TRUE;
}
boolean appendElement(LINEAR *head, USER_TYPE data) {
return insertElementAt(head, head->count, data);
}
boolean removeElement(LINEAR *head, int index, USER_TYPE *data) {
if (NULL == head || isLinearEmpty(head)
|| index < 0 || index >= head->count) {
return FALSE;
}
*data = head->data[index];
for (; index < head->count; index++) {
head->data[index] = head->data[index + 1];
}
head->count--;
return TRUE;
}
void clearLinear(LINEAR *head) {
head->count = 0;
}
int getIndexOfElement(LINEAR *head, USER_TYPE data,
boolean (*eq)(USER_TYPE,USER_TYPE)) {
int index;
int count = getCount(head);
if (NULL == head || isLinearEmpty(head)) {
return NOT_FOUND;
}
for (index = 0; index < count; index++) {
if (eq(head->data[index],data)) {
return index;
}
}
return NOT_FOUND;
}
测试代码demo.c
#include <stdio.h>
#include "linear.h"
#include "polynomial.h"
int main(int argc, char const *argv[]) {
POLYNOMIAL *polyOne = NULL;
POLYNOMIAL *polyAnother = NULL;
POLYNOMIAL *result = NULL;
initPolynomial(&polyOne, 30);
printf("以下录入第一个多项式:\n");
enterPolynomial(polyOne);
printf("以下为输入的第一个多项式:\n");
showPolynomial(polyOne);
initPolynomial(&polyAnother, 30);
printf("以下录入第二个多项式:\n");
enterPolynomial(polyAnother);
printf("以下为输入的第二个多项式\n");
showPolynomial(polyAnother);
result = addPolynomial(polyOne, polyAnother);
printf("以下为两个多项式之和:\n");
showPolynomial(result);
destoryPolynomial(&polyOne);
destoryPolynomial(&polyAnother);
destoryPolynomial(&result);
return 0;
}