前言
数据结构,顾名思义就是数据与数据的关系。这个关系可以分为两种:线性关系和非线性关系。
线性关系可以理解为一对一的关系,也可前言
数据结构,顾名思义就是数据与数据的关系。这个关系可以分为两种:线性关系和非线性关系。
线性关系可以理解为一对一的关系,也可理解为数学上的满射。
非线性关系就是一对多或者多对多,例如:树
而数据结构也分为逻辑结构和物理结构;
逻辑结构:人文思想层面的解决问题、安排数据间关系的结果
物理结构:对逻辑结构的存储、表达和实现,是逻辑结构的计算机存储方式。
物理结构(存储结构)分为线性和非线性存储:
线性存储:使用连续存储空间存储数据。如:数组
非线性存储:使用非连续存储空间存储数据。如:链表。
而我现在使用的就是线性存储。但又引出一个问题:这个数组应该定义多大呢?数组的元素类型是什么类型的?我们可以使用一个结构体来包含这些元素。那么,这个数组的大小应该由用户来自定义。但是当我们确定了这个数组空间大小后,我们也应该知道在这个数组的有效元素空间为多少。这里包含了好几个元素:数组,数组容量,数组有效个数。
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于机房。