概念
采用顺序存储结构的线性表。
用一组地址连续的存储单元依次存储线性表的数据元素,以元素在计算机中物理位置来表示数据元素之间的逻辑关系。与数组类似,在于对数据元素的定义可以不局限与数字或字符,可以利用结构体完成各种不同的运算,例如复数 (a + bi) 的加减乘除。
准备工作
创建线性表 (以复数线性表为例)
typedef struct
{
double rp, ip;
} COMPLEX;
定义COMPLEX结构体,包含rp实部, ip虚部。
typedef COMPLEX LELEMENT;
将COMPLEX定义为线性表元素LELEMENT,方便以后可以将复数线性表改为其他线性表,例如分数线性表。
#ifndef _Real_h_
#define _Real_h_
#define epsilon 1e-8
double Revise(double x);
void RealInput(double *x);
void RealOutput(double x);
int RealGt(double x, double y);
int RealGe(double x, double y);
int RealLt(double x, double y);
int RealLe(double x, double y);
int RealEq(double x, double y);
int RealNe(double x, double y);
void RealSwap(double*x, double *y);
#endif
进行实数准备工作,如实数误差修正,实数输入输出,比较大小,判断相等,交换。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "Real.h"
double Revise(double x)
{
if (fabs(x) < epsilon)
{
return 0;
}
else
{
return x;
}
}
void RealInput(double *x)
{
scanf("%lf", &*x);
*x = Revise(*x);
}
void RealOutput(double x)
{
printf("%g", Revise(x));
}
int RealGt(double x, double y)
{
int t=0;
if((x-y)>=epsilon)
{
t=1;
}
return t;
}
int RealGe(double x, double y)
{
int t=0;
if((x-y)>=epsilon||fabs(x-y)<epsilon)
{
t=1;
}
return t;
}
int RealLt(double x, double y)
{
int t=0;
if((y-x)>=epsilon)
{
t=1;
}
return t;
}
int RealLe(double x, double y)
{
int t=0;
if((y-x)>=epsilon||fabs(x-y)<epsilon)
{
t=1;
}
return t;
}
int RealEq(double x, double y)
{
int t=0;
if(fabs(x-y)<epsilon)
{
t=1;
}
return t;
}
int RealNe(double x, double y)
{
int t=0;
if(fabs(x-y)>=epsilon)
{
t=1;
}
return t;
}
void RealSwap(double *x, double *y)
{
double a;
a = *x;
*x = *y;
*y = a;
}
进行线性表元素准备工作。
#ifndef _LElement_h_
#define _LElement_h_
#include "Complex.h"
typedef COMPLEX LELEMENT;
void LElementInput(LELEMENT *x);
void LElementOutput(const LELEMENT *x);
int LElementEq(const LELEMENT *x, const LELEMENT *y);
int LElementNe(const LELEMENT *x, const LELEMENT *y);
void LElementSwap(LELEMENT *x, LELEMENT *y);
#endif
由于复数无法比较大小,所以只有输入输出,判断相等,交换函数。
#include <stdio.h>
#include <stdlib.h>
#include "LElement.h"
void LElementInput(LELEMENT *x)
{
ComplexInput(x);
}
void LElementOutput(const LELEMENT *x)
{
ComplexOutput(x);
}
int LElementEq(const LELEMENT *x, const LELEMENT *y)
{
return ComplexEq(x, y);
}
int LElementNe(const LELEMENT *x, const LELEMENT *y)
{
return ComplexNe(x, y);
}
void LElementSwap(LELEMENT *x, LELEMENT *y)
{
ComplexSwap(x, y);
}
顺序表
在开始之前,我们已经创建了Real.h、Real.c、LElement.h、LElement.c文件,现在开始构建顺序表
typedef struct
{
int size, length;
LELEMENT *element;
} ALIST;
包含有线性表的尺寸,线性表的长度,还有线性表元素的起始地址*element。
#ifndef _AList_h_
#define _AList_h_
#include "LElement.h"
#define AListInitSize 1024//初始尺寸
#define AListIncrement 128//新增尺寸
typedef struct
{
int size, length;
LELEMENT *element;
} ALIST;
void AListCreate(ALIST *list);//创建
void AListDestroy(ALIST *list);//销毁
void AListResize(ALIST *list, int size);//扩容
void AListInsert(ALIST *list, int index, const LELEMENT *element);插入
void AListOutput(const ALIST *list);//输出
void AListRemove(ALIST *list, int index, LELEMENT *element);输入
void AListClear(ALIST *list);//清空
void AListInput(ALIST *list);//输入
int AListEmpty(const ALIST *list);//判空
int AListLength(const ALIST *list);//长度
void AListSet(ALIST *list, int index, const LELEMENT *element);设置
void AListGet(const ALIST *list, int index, LELEMENT *element);获取
#endif
在程序开始前,我们需创建线性表才能开始使用,在程序结束前,应将创建的线性表销毁。在线性表初始尺寸不够容纳我们的数据元素时,我们对线性表进行扩容。而根据使用需求,有插入、输出、删除元素、输入、输出线性表、清空线性表、判断空表,获取长度,设置、获取数据元素。
#include <stdio.h>
#include <stdlib.h>
#include "AList.h"
void AListCreate(ALIST *list)
{
list->size = AListInitSize;
list->length = 0;
list->element = (LELEMENT*)malloc(list->size * sizeof(LELEMENT));
}
void AListDestroy(ALIST *list)
{
free(list->element);
list->element = NULL;
list->size = list->length = 0;
}
void AListResize(ALIST *list, int size)
{
int i;
LELEMENT *element;
if (size > list->length && size != list->size)
{
list->size = size;
element = (LELEMENT*)malloc(list->size * sizeof(LELEMENT));
for (i = 0; i < list->length; i++)
{
element[i] = list->element[i];
}
free(list->element);
list->element = element;
}
}
void AListInsert(ALIST *list, int index, const LELEMENT *element)
{
int i;
if (index < 1 || index > list->length + 1)
{
printf("Incorrect index!\n");
}
else
{
if (list->length == list->size)
AListResize(list, list->size + 1);
for (i = list->length; i > index - 1; i--)
{
list->element[i] = list->element[i - 1];
}
list->element[index - 1] = *element;
list->length++;
}
}
void AListOutput(const ALIST *list)
{
int i;
putchar('(');
for (i = 0; i < list->length; i++)
{
if (i)
{
putchar(',');
}
putchar(' ');
LElementOutput(&list->element[i]);
}
putchar(' ');
putchar(')');
}
void AListRemove(ALIST *list, int index, LELEMENT *element)
{
int i;
LELEMENT x = list->element[index - 1];
if (index <= list->length && index > 0)
{
for (i = index - 1; i < list->length - 1; i++)
{
list->element[i] = list->element[i + 1];
}
list->length--;
*element = x;
}
else
{
printf("Incorrect index!\n");
}
}
void AListClear(ALIST *list)
{
if (list->element != NULL)
list->length = 0;
}
void AListInput(ALIST *list)
{
char c;
LELEMENT element;
AListClear(list);
scanf(" (");
while (scanf(" %c", &c),c != ')')
{
ungetc(c, stdin);
if (list->length)
scanf(",");
LElementInput(&element);
if (list->length == list->size)
AListResize(list ,list->size + 10);
list->element[list->length] = element;
++list->length;
}
}
int AListEmpty(const ALIST *list)
{
return !list->length;
}
int AListLength(const ALIST *list)
{
return list->length;
}
void AListSet(ALIST *list, int index, const LELEMENT *element)
{
if (index <= list->length && index > 0) list->element[index - 1] = *element;
else printf("Incorrect index!\n");
}
void AListGet(const ALIST *list, int index, LELEMENT *element)
{
if (index <= list->length && index > 0) *element = list->element[index - 1];
else printf("Incorrect index!\n");
}
完成线性表的创建和一系列对线性表的操作后,我们需要创建一操作面版提示用户如何操作
#include <stdio.h>
#include "AList.h"
int main()
{
int index;
LELEMENT element;
ALIST list;
char c;
AListCreate(&list);
printf("E-判空 L-长度 N-插入 R-删除 C-清空 S-设置 G-读取 I-输入 O-输出 Q-退出 > ");
scanf(" %c", &c);
while (c != 'q' && c != 'Q')//退出
{
if (c == 'e' || c == 'E')//空
{
if (AListEmpty(&list))
printf("空表\n");
else
printf("非空表\n");
}
else if (c == 'l' || c == 'L')//长
{
printf("长度: %d\n", AListLength(&list));
}
else if (c == 'i' || c == 'I')//输入
{
printf("线性表: ");
AListInput(&list);
}
else if (c == 'n' || c == 'N')//插入
{
printf("位序: ");
scanf("%d", &index);
printf("数据元素: ");
LElementInput(&element);
AListInsert(&list, index, &element);
}
else if (c == 'r' || c == 'R')//删除
{
printf("位序: ");
scanf("%d", &index);
AListRemove(&list, index, &element);
printf("数据元素: ");
LElementOutput(&element);
putchar('\n');
}
else if (c == 'c' || c == 'C')//清空
{
AListClear(&list);
}
else if (c == 's' || c == 'S')//设置
{
printf("位序: ");
scanf("%d", &index);
printf("数据元素: ");
LElementInput(&element);
AListSet(&list, index, &element);
}
else if (c == 'g' || c == 'G')//读取
{
printf("位序: ");
scanf("%d", &index);
AListGet(&list, index, &element);
printf("数据元素: ");
LElementOutput(&element);
putchar('\n');
}
else if (c == 'o' || c == 'O')//输出
{
printf("线性表: ");
AListOutput(&list);
putchar('\n');
}
else
{
printf("不正确的选项!\n");
}
printf("E-判空 L-长度 N-插入 R-删除 C-清空 S-设置 G-读取 I-输入 O-输出 Q-退出 > ");
scanf(" %c", &c);
}
AListDestroy(&list);
return 0;
}
这样一个复数线性表就基本完成了。后期我们需要做其他线性表的时候,不必大刀阔斧对程序进行修改,只需要改变一些关键内容,例如将复数线性表改成分数线性表时,我们将
typedef COMPLEX LELEMENT;
改为
typedef FRACTION LELEMENT;
并将实数函数改为整数函数,并添加关于分数运算的函数,如求最大公约数
int Gcd(int x, int y)
{
if (x || y)
{
int a = IntMax(x, y), b = IntMin(x, y), c;
if (a < 0) a = -a;
if (b < 0) b = -b;
while (b > 0)
{
c = a % b;
a = b;
b = c;
}
return a;
}
else
{
return 1;
}
}
最大公倍数
int Lcm(int x, int y)
{
if (x < 0) x = -x;
if (y < 0) y = -y;
return x * y / Gcd(x, y);
}
比较大小
int LElementGt(const LELEMENT *x, const LELEMENT *y)
{
LELEMENT a = *x, b = *y;
return FractionGt(&a, &b);
}
int LElementGe(const LELEMENT *x, const LELEMENT *y)
{
LELEMENT a = *x, b = *y;
return FractionGe(&a, &b);
}
int LElementLt(const LELEMENT *x, const LELEMENT *y)
{
LELEMENT a = *x, b = *y;
return FractionLt(&a, &b);
}
int LElementLe(const LELEMENT *x, const LELEMENT *y)
{
LELEMENT a = *x, b = *y;
return FractionLe(&a, &b);
}
及其他可用于分数的运算,但不可用于复数运算的函数。