利用线性表工具完成多项式相加

前言

数据结构,顾名思义就是数据与数据的关系。这个关系可以分为两种:线性关系和非线性关系。
线性关系可以理解为一对一的关系,也可前言
数据结构,顾名思义就是数据与数据的关系。这个关系可以分为两种:线性关系和非线性关系。
线性关系可以理解为一对一的关系,也可理解为数学上的满射。
非线性关系就是一对多或者多对多,例如:树

而数据结构也分为逻辑结构和物理结构;
逻辑结构:人文思想层面的解决问题、安排数据间关系的结果
物理结构:对逻辑结构的存储、表达和实现,是逻辑结构的计算机存储方式。

物理结构(存储结构)分为线性和非线性存储:
线性存储:使用连续存储空间存储数据。如:数组
非线性存储:使用非连续存储空间存储数据。如:链表。

而我现在使用的就是线性存储。但又引出一个问题:这个数组应该定义多大呢?数组的元素类型是什么类型的?我们可以使用一个结构体来包含这些元素。那么,这个数组的大小应该由用户来自定义。但是当我们确定了这个数组空间大小后,我们也应该知道在这个数组的有效元素空间为多少。这里包含了好几个元素:数组,数组容量,数组有效个数。

LINEAR工具的实现

经过前面可知,我们应该定义一个结构体去包含这些元素。

typedef struct LINEAR{
	USER_TYPE *data;//由用户自己定义数组的元素类型
	int capacity;//数组的容量
	int count;//有效元素个数
}LINEAR;

我们在主函数调用这个结构体时,可以用一个控制头去控制这个结构体,这样就避免了使用者改变我的工具。

在这里插入图片描述

在画出我们这个工具的简示图后,我们应该去思考通过这个结构体去完成某些事情。
1、初始化线性表由于我们是申请的空间
2、为了避免造成内存泄漏,程序结束时,我们也应该释放申请的空间,即销毁线性表
3、判断线性表是否为空
4、判断线性表是否已满
5、取得线性表有效元素个数
6、取得线性表容量
7、在控制头所指向的线性表中,取得下标为index的元素的值
8、在控制头所指向的线性表中,给下标为index的元素赋值为data的值
9、在控制头所指向的线性表中,寻找data元素的下标(需要用到相等比较)
10、在控制头所指向的线性表中,在下标为index的元素插入一个data
11、在控制头所指向的线性表的末尾,完成追加data
12、在控制头所指向的线性表中,在指定下标index的位置上,删除元素
13、用户定义自己的相等比较函数(因为我们无法得知用户会申请什么元素的空间)

此时,控制头所指向的空间应该多一个元素,来进行相等比较。

typedef boolean (*EQU_FUN)(USER_TYPE, USER_TYPE);//指向函数的指针
typedef struct LINEAR{
	USER_TYPE *data;//由用户自己定义数组的元素类型
	int capacity;//数组的容量
	int count;//有效元素个数
	EQU_FUN compare;
}LINEAR;

linear.h

//初始化线性表
boolean InitLinear(LINEAR **head, int capacity);
//销毁线性表
boolean DestoryLinera(LINEAR **head);
//判线性表空
boolean isEmptyLinear(const LINEAR *head);
//判线性表满
boolean isFullLinear(const LINEAR *head);
//取得有效元素个数
int getElementCount(const LINEAR *head);
//取得线性表容量
int getLinearCapacity(const LINEAR *head);
//在head所指向的线性表中,取下标为index的元素的值
boolean getElementResult(const LINEAR *head, const int index, USER_TYPE *data); 
//在head所指向的线性表中,将给下标为index的元素赋值为data的值
boolean setElementResult(const LINEAR *head, const int index, USER_TYPE data);
//在head所指向的线性表中,寻找值data元素的下标
int SearchElement(const LINEAR *head, USER_TYPE data);
//在head所指向的线性表中,在下标为index的元素插入一个data
boolean insortElementResult(LINEAR *head, int index, USER_TYPE data);
//在head所指向的线性表的末尾,追加data
boolean appendElement(LINEAR *head, USER_TYPE data);
//在head所指向的线性表中,在指定下标index的位置上,删除元素
boolean DeleteElementResult(LINEAR *head, int index);
//用户定义自己的相等比较函数
void setEquals(LINEAR *head, const EQU_FUN userEquals);

mec.h

typedef unsigned char		boolean;
typedef boolean				u8;
typedef unsigned short		u16;
typedef unsigned int		u32;

#define TRUE		1
#define FALSE		0

#define NOT_FOUND	-1

linear.c

#include <stdio.h>
#include <malloc.h>

#include "userType.h"
#include "mec.h"
#include "linear.h"

static boolean CompareElement(USER_TYPE one, USER_TYPE other);

//默认相等比较原则,切片比较,即,一个字节一个字节进行比较
static boolean CompareElement(USER_TYPE one, USER_TYPE other){
	u8 *p = (u8 *)&one;
	u8 *q = (u8 *)&other;
	int size = sizeof(USER_TYPE);
	int i = 0;
	
	//如果有字节的值不同,返回错误,否则,指针继续向后移动
	for(i; i < size; i++) {
		if(*p != *q) {
			return FALSE;
		}
		++p;
		++q;
	}

	return TRUE;
}

boolean InitLinear(LINEAR **head, int capacity) {
	//head有效性判断
	if(NULL == head && NULL != *head) {
		return FALSE;
	}

	*head = (LINEAR *)calloc(sizeof(LINEAR),1);
	(*head)->data = (USER_TYPE *)calloc(sizeof(USER_TYPE),capacity);//申请capacit个USER_TYPE类型的空间
	(*head)->capacity = capacity;//记录空间大小
	(*head)->count = 0;//刚开始有效元素个数为0
	(*head)->compare = CompareElement;//指向默认比较函数,以后可以更改

	return TRUE;
}

boolean DestoryLinera(LINEAR **head) {
	if(NULL == head || NULL == *head) {
		return FALSE;
	}

	//应该先释放data所指向的空间,若直接释放head所指向的空间,会造成data所指向的空间无法释放,会造成内存泄漏
	free((*head)->data);
	free(*head);
	*head = NULL;

	return TRUE;
}

boolean isEmptyLinear(const LINEAR *head) {
	return NULL == head || head->count <= 0;//短路运算,若head==NULL,有效元素必然为空
}

boolean isFullLinear(const LINEAR *head) {
	return NULL == head || head->capacity == head->count;//短路运算,若head==NULL,元素空间判断为满
}

int getElementCount(const LINEAR *head){
	return head->count;
}

int getLinearCapacity(const LINEAR *head) {
	return head->capacity;
}

boolean getElementResult(const LINEAR *head, const int index, USER_TYPE *data) {
	if(NULL == head || index < 0 || index >= head->count) {
		return FALSE;
	}

	*data = head->data[index];//将下标为index的值赋值给data所指向的空间

	return TRUE;
}

boolean setElementResult(const LINEAR *head, const int index, USER_TYPE data) {
	if(NULL == head || index < 0 || index >= head->count) {
		return FALSE;
	}

	head->data[index] = data;//将data赋值给下标为index的空间

	return TRUE;
}

int SearchElement(const LINEAR *head, USER_TYPE data) {
	int index = 0;

	for(index; index < head->count; index++) {
		if(TRUE == head->compare(head->data[index],data)){
			return index;
		}
	}
	return NOT_FOUND;
}

boolean insortElementResult(LINEAR *head, int index, USER_TYPE data) {
	int i;

	if(NULL == head || index < 0 || index > head->count || isFullLinear(head)) {
		return FALSE;
	}
	
	for(i = head->count-1; i >= index; i--) {
		head->data[i+1] = head->data[i];
	}
	head->data[index] = data;
	head->count++;

	return TRUE;
}

boolean appendElement(LINEAR *head, USER_TYPE data) {
	return insortElementResult(head, head->count,data);
}

boolean DeleteElementResult(LINEAR *head, int index) {
	int i;

	if(NULL == head || index < 0 || index >= head->count || isEmptyLinear(head)) {
		return FALSE;
	}

	for(i = index; i < head->count-1; i++) {
		head->data[i] = head->data[i+1];
	}
	--head->count;

	return TRUE;
}

void setEquals(LINEAR *head, const EQU_FUN userEquals) {
	head->compare = userEquals;
}


三、POLYNOMIAL的实现

在完成这个linear工具后,我们开始使用这个工具去完成多项式相加。如何实现呢?在完成polynomial的过程中,去调用linear里的函数。现在我们考虑的方向就是完成这个多项式相加,即只需考虑完成多项式相加的具体过程。
在数学中,多项式(polynomial)是指由变量、系数以及它们之间的加、减、乘、幂运算(非负整数次方)得到的表达式。
例如:4x∧5-2x∧3+5x-1
那么,在USER_TYPE.h文件中,我们应该去自己定义

typedef struct POLY_ITEM{
	double coefficient;//系数
	int power;//指数
}POLY_ITEM, USER_TYPE;

现在需要完成的功能是:
1、初始化

boolean InitPolynomial(POLYNOMIAL **head, int capacity);

2、销毁

boolean DestoryPolynomial(POLYNOMIAL **head);

3、获取多项式的有效元素个数

int getPolyItemCount(const POLYNOMIAL *head);

4、追加多项式的一项

boolean AppendElement(POLYNOMIAL *head, POLY_ITEM item);

5、获取多项式的下标为index的某一项

boolean getPolymentElement(const POLYNOMIAL *head,const int index, POLY_ITEM *item);

6、打印输入的多项式

void PrintfPolyItem(POLYNOMIAL *head);

7、完成多项式相加

void addPolynomial(POLYNOMIAL *one, POLYNOMIAL *other, POLYNOMIAL **result);

在这里我将输入多项式放在了主函数。原因是他与主函数的联系是较为紧密的。

void inputPolyitem(POLYNOMIAL *head) {
	int index = 0;
	double coefficient;
	int power;
	POLY_ITEM item;

	printf("第%d项:",++index);
	scanf("%lf %d",&coefficient,&power);
	
	//若系数为0,结束输入
	while(fabs(coefficient) > 1e-6){
		item.coefficient = coefficient;
		item.power = power;
		AppendElement(head,item);

		printf("第%d项:",++index);
		scanf("%lf %d",&coefficient,&power);		
	}
}

现给出polynomial的完整代码
polynomial.h

#ifndef _MEC_POLYITEM_H_
#define _MEC_POLYITEM_H_ 

#include "Linear\\mec.h"
#include "Linear\\userType.h"
#include "Linear\\linear.h"

typedef LINEAR POLYNOMIAL;

int compareItem(POLY_ITEM one, POLY_ITEM other);//自定义的相等比较函数
boolean eqPolyItem(POLY_ITEM one, POLY_ITEM other);
boolean InitPolynomial(POLYNOMIAL **head, int capacity);
boolean DestoryPolynomial(POLYNOMIAL **head);
boolean isPolynomialEmpty(const POLYNOMIAL *head);
boolean AppendElement(POLYNOMIAL *head, POLY_ITEM item);
int getPolyItemCount(const POLYNOMIAL *head);
boolean getPolymentElement(const POLYNOMIAL *head,const int index, POLY_ITEM *item);
void PrintonePolyItem(const POLY_ITEM item, boolean isfirst);
void PrintfPolyItem(POLYNOMIAL *head);
void addPolynomial(POLYNOMIAL *one, POLYNOMIAL *other, POLYNOMIAL **result);

#endif

polynomial.c

#include <stdio.h>
#include <math.h>

#include "Linear\\mec.h"
#include "Linear\\userType.h"
#include "Linear\\linear.h"
#include "polynomial.h"

//在多项式中,只需比较指数部分
int compareItem(POLY_ITEM one, POLY_ITEM other){
	return one.power - other.power;
}

boolean eqPolyItem(POLY_ITEM one, POLY_ITEM other) {
	return compareItem(one,other) == 0;
}

boolean InitPolynomial(POLYNOMIAL **head,int capacity) {
	int ok;
	ok = InitLinear(head, capacity);
	if(ok) {
		setEquals(*head,eqPolyItem);
	}
	return ok;
}

//这里调用了linear的函数,更加可以说明,工具制造出来就是被使用的
boolean DestoryPolynomial(POLYNOMIAL **head) {
	return DestoryLinera(head);
}

boolean isPolynomialEmpty(const POLYNOMIAL *head) {
	return isEmptyLinear(head);
}


boolean AppendElement(POLYNOMIAL *head, POLY_ITEM item) {
	return appendElement(head,item);
}

int getPolyItemCount(const POLYNOMIAL *head) {
	return	getElementCount(head);
}

boolean getPolymentElement(const POLYNOMIAL *head,const int index, POLY_ITEM *item) {
	return getElementResult(head, index, item);
}

void PrintonePolyItem(const POLY_ITEM item,boolean isfirst) {
	//判断是否是第一个多项式并且系数是否大于0,如果都满足,输出'+'
	if(!isfirst && item.coefficient > 1e-6) {
		printf("+");
	}
	
	//指数为0,直接输出系数部分
	if(item.power == 0){
		printf("%lg",item.coefficient);
	} else if(fabs(item.coefficient - 1) < 1e-6) {
		//判断系数为1,不输出系数
		;
	} else if(fabs(item.coefficient + 1) < 1e-6) {
		//判断系数为-1,输出'-'
		printf("-");
	} else {
		printf("%lg",item.coefficient);
	}

	if(item.power > 1){
		printf("x^%d",item.power);
	} else if(item.power == 1) {
		printf("x");
	}
}

void PrintfPolyItem(POLYNOMIAL *head) {
	POLY_ITEM item;
	int count = getPolyItemCount(head);
	int index = 0;

	if (NULL == head || isPolynomialEmpty(head)) {
		return;
	}

	for(index; index < head->count; index++){
		getPolymentElement(head,index,&item);
		PrintonePolyItem(item,index == 0);//根据index==0来判断是否是第一次使用
	}
}

void addPolynomial(POLYNOMIAL *one, POLYNOMIAL *other, POLYNOMIAL **result) {
	POLYNOMIAL *res = NULL;
	int oneIndex = 0;
	int otherIndex = 0;
	int oneCount = getPolyItemCount(one);//获取第一个多项式有效元素个数
	int otherCount = getPolyItemCount(other);//获取第二个多项式有效元素个数
	int eq;
	double x;
	POLY_ITEM oneItem;
	POLY_ITEM otherItem;
	POLY_ITEM resItem;
	
	//根据两个多项式的有效元素个数去申请最大空间
	InitPolynomial(&res, oneCount + otherCount);

	getPolymentElement(one, oneIndex, &oneItem);
	getPolymentElement(other, otherIndex, &otherItem);

	while(oneIndex < oneCount && otherIndex < otherCount) {
		eq = compareItem(oneItem, otherItem);
		//第一个多项式的项大于第二个多项式的项,将第一个多项式的项追加到res的末尾
		if (eq > 0) {
			AppendElement(res, oneItem);
			getPolymentElement(one, ++oneIndex, &oneItem);
		} else if (eq < 0) {
		//第二个多项式的项大于第一个多项式的项,将第二个多项式的项追加到res的末尾
			AppendElement(res, otherItem);
			getPolymentElement(other, ++otherIndex, &otherItem);
		}	else {
			x = oneItem.coefficient + otherItem.coefficient;
			//指数相等时,判断系数是否为0,不为0执行以下操作
			if(fabs(x) > 1e-6) {
				resItem.coefficient = x;
				resItem.power = oneItem.power;
				AppendElement(res, resItem);
			}
			
			//无论系数之和是否为0,此时都应该取下一项
			getPolymentElement(one, ++oneIndex, &oneItem);
			getPolymentElement(other, ++otherIndex, &otherItem);
		}
	}

	//判断第一个多项式是否全部遍历完,若没有,继续将第一个多项式剩余的元素追加到res
	while(oneIndex < oneCount) {
		AppendElement(res, oneItem);
		getPolymentElement(one, ++oneIndex, &oneItem);
	}
	//判断第二个多项式是否全部遍历完,若没有,继续将第二个多项式剩余的元素追加到res
	while(otherIndex < otherCount) {
		AppendElement(res, otherItem);
		getPolymentElement(other, ++otherIndex, &otherItem);
	}

	*result = res;//将res所指向的空间的首地址赋值给*result
}

四,完成多项式相加

在完成上面所有的准备工作后,我们就可以在主函数里调用他了,此时,主函数的调用变得非常简单。

int main( )
{
	POLYNOMIAL *polyA = NULL;
	POLYNOMIAL *polyB = NULL;
	POLYNOMIAL *polyC = NULL;

	InitPolynomial(&polyA,30);
	InitPolynomial(&polyB,30);

	printf("请输入第一个多项式:\n");
	inputPolyitem(polyA);
	printf("请输入第二个多项式:\n");
	inputPolyitem(polyB);

	printf("多项式A:");
	PrintfPolyItem(polyA);
	printf("\n");
	printf("多项式B:");
	PrintfPolyItem(polyB);
	printf("\n");

	addPolynomial(polyA, polyB, &polyC);
	printf("多项式A + 多项式B:");
	PrintfPolyItem(polyC);
	printf("\n");

	DestoryPolynomial(&polyA);
	DestoryPolynomial(&polyB);
	DestoryPolynomial(&polyC);

	return 0;
}

运行结果
在这里插入图片描述
这是我第一次完成的一个项目,在完成这个项目时,我深刻的体会到想和做是存在很大的差距的,很多事看起来简单,但在实现起来却是困难重重。

笔者水平有限,目前只能描述以上问题,如果有其他情况,可以留言,有错误,请指教,有继续优化的,请分享,谢谢!
2020.07.19于机房。

猜你喜欢

转载自blog.csdn.net/weixin_45483328/article/details/107434284