前言
本文介绍线性表在图书管理系统程序中的应用。通过模块化设计过程,设计出高效的算法完成各种操作任务,针对实际数据实现各种操作。
一、数据结果说明
(1)结点的定义
typedef struct
{
char no[20]; //图书编号
char name[50]; //图书名称
float price; //图书价格
}Book;
typedef struct
{
Book *elem; //存储空间的基地址
int length; //当前图书的个数
}SqList;
首先,创建一个结构体来存储图书信息,结构体中包含图书编号、书名和定价;其中编号和书名可以用char类型的数组来存储,而定价因为可能有小数部分,所以需要float类型来定义,接下来就是创建顺序表节点,该结构体有两个成员变量,Book *elem和int length,elem里边存放的是书籍的三个信息,length是记录当前图书的个数,即此时顺序表的长度。
(2)宏定义和程序中使用的各变量的类型
typedef int Status //Status是函数返回值的类型,其值是函数结果状态代码
#define MAXSIZE 100 //图书表的最大长度
#define OVERFLOW 0 //用于函数返回值,判断是否运行状态
#define OK 1
#define ERROR -1
#include<string.h>
说明:在程序中需要用到字符串比较函数和字符串拷贝函数,所以需要添加此头文件。
二、详细设计
(1)初始化
顺序表的初始化操作就是构造一个空的顺序表
【算法步骤】
①为顺序表L动态分配一个预定义大小的数组空间,使elem指向这段空间的基地址。
②将表的当前长度设为0。
【算法实现】
Status InitList(SqList &L)
{
L.elem=new Book[MAXSIZE]; //分配一个大小为 MAXSIZE的数组空间 ,类型为Book
if(!L.elem)
{
return OVERFLOW; //分配失败退出
}
L.length=0; //空表表长为0
return OK;
}
(2)取值
取值操作是根据指定的位置序号i,获取顺序表中第i个数据元素的值。
【算法步骤】
①判断指定的位置序号i值是否合理(1<=i<=L.length),若不合理,则返回ERROR。
②若i值合理,则将第i个数据元素L.elem[i-1]赋值给参数e,通过e返回第i个数据元素的传值。
【算法实现】
Status GetElem(SqList &L,int i,Book &e)
{
//按位置取值,先检查位置序号i是否合理(1<=i<=length),不合理,就返回ERROR
//若合理,就把L.elem[i-1]元素赋值给参数e
if(i<1||i>L.length)
{
return ERROR;
}
e=L.elem[i-1];
return OK;
}
(3)查找
查找操作是根据指定的元素值e,查找顺序表中第1个值与e相等的元素。若查找成功,则返回该元素在表中的位置序号,若查找失败,则返回0。
【算法步骤】
①从第一个元素起,依次将其值和e相比较,若找到值与e相等的元素L.elem[i],则查找成功,返回该元素的序号i+1。
②若查遍整个顺序表都没有找到,则查找失败,返回0。
【算法实现】
Status LocateElem(SqList &L,char e[] )
{
//遍历数组,挨个查找
int i;
for(i=0;i<L.length;i++)
{
if(strcmp(L.elem[i].name,e)==0)
{
return i+1; //找到就返回位置序号
}
}
return 0; //查找失败,返回0
}
(4)插入
插入操作是指在表的第i个位置插入一个新的数据元素e,使长度为n的线性表变成长度为n+1的线性表。
【算法步骤】
①判断插入位置i是否合法(i值的合法范围数1<=i<=n+1),若不合法则返回ERROR。
②判断顺序表的存储空间是否已满,若满则返回ERROR。
③将第n个至第i个位置的元素依次向后移动一个位置,空出第i个位置(i=n+1是无须移动)。
④将要插入的新元素e放在第i个位置上。
⑤表长加1。
【算法实现】
Status ListInsert(SqList &L,int i,Book e)
{
//检查位置i是否合法
if(i<1||i>L.length+1)
{
return ERROR; //i值不合法,返回ERROR
}
//检查表是否已满
if(L.length==MAXSIZE)
{
return ERROR; //当前存储空间已满
}
//将第n个至第i个位置上的元素后移,空出第i个位置
int j;
for(j=L.length-1;j>=i-1;j--)
{
L.elem[j+1]=L.elem[j];
}
//把元素e放在第i个位置上
strcpy(L.elem[i-1].no,e.no);
strcpy(L.elem[i-1].name,e.name);
L.elem[i-1].price=e.price;
//表长加1
++L.length;
return OK;
}
(5)删除
线性表的删除操作是指将表的第i个元素删去,将长度为n的线性表变成长度为n-1的线性表。
【算法步骤】
①判断删除位置i是否合法(合法值为1<=i<=n),若不合法则返回ERROR。
②将第i+1个至第n个元素依次向前移动一个位置(i=n时无法移动)。
③表长减1。
【算法实现】
Status ListDelete(SqList &L,int i)
{
//检查是否为空表
if(L.length==0)
{
return ERROR; //空表返回ERROR
}
//检查位置i是否合法
if(i<1||i>L.length)
{
return ERROR; //不合法返回ERROR
}
//将第i至第n个位置上的元素前移,覆盖第i个位置上的元素
int j;
for(j=i;j<=L.length-1;j++)
{
L.elem[j-1]=L.elem[j];
}
//表长减1
--L.length;
return OK;
}
(6)输出
输出操作是把顺序表中的内容按表中的顺序输出。
【算法步骤】
①判断顺序表是否为空,若为空表则返回ERROR。
②遍历数组,输出图书信息。
【算法实现】
Status BookInformation(SqList &L)
{
//检查是否为空表
if(L.length==0)
{
printf("你没有存入图书信息\n");
return ERROR;
}
//遍历数组
int j;
printf("\n\n*******************图书展示**********************\n\n");
for(j=0;j<L.length;j++)
{
printf("%s\t%s\t%f\n\n\n",L.elem[j].no,L.elem[j].name,L.elem[j].price);
}
return OK;
}
三、调试与测试
在测试函数功能前,先输入一些图书信息,保存在顺序表中,便于后面的测试。
这里我键入了五本图书的信息。
可以看到初始化函数运行成功,第一行给出了提示信息,成功建立了一个空表。
(1)取值函数的测试
这里我测试了3次按位置取值,出入要查询的位置序号,最后输出该位置上的图书信息。测试结构均正确。
(2)查找函数的测试
测试中查找了两次,给出要查找的书名,最后显示这本书在顺序表中的序号。
测试结果正确。
(3)插入函数的测试
测试中添加了一本书,放在第6号位置,依次给出编号、书名、价格。
然后显示运行状态,运行状态显示添加图书成功。后面我又调用了输出函数,把表中的图书信息全输出来,可以看到,添加的这本书在顺序表中,确定添加成功。
(4)删除函数的测试
这里把刚才添加在6号位置上的图书删除,还是一样的给出位置序号,显示运行状态,显示删除成功。然后又调用了输出函数,可以看到,6号位置上的图书不在表中了,已确定被删除。
(5)输出函数的测试
输出函数在前面几个测试中已经用到了,这里就把最后在表中的图书信息输出。
四、附录(程序清单)
#include<stdio.h>
#include<string.h>
#define MAXSIZE 100 //图书表的最大长度
#define OVERFLOW 0
#define OK 1
#define ERROR -1
typedef struct
{
char no[20]; //图书编号
char name[50]; //图书名称
float price; //图书价格
}Book;
typedef struct
{
Book *elem; //存储空间的基地址
int length; //当前图书的个数
}SqList;
typedef int Status; //用 Status代替int
Status InitList(SqList &L); //初始化
Status GetElem(SqList &L,int i,Book &e); //按位置取值
Status LocateElem(SqList &L,char e[]); //按书名查找,找到就返回图书在表中的位置序号,没找到,返回0
Status ListInsert(SqList &L,int i,Book e); //在第i个位置插入新的元素e
Status ListDelete(SqList &L,int i); //删除第i个位置上的元素
Status BookInformation(SqList &L); //输出图书的所以信息
int main(void)
{
SqList L;
Book e;
char ch[20];
int n=0;
int g=0;
InitList(L);
if(InitList(L))
{
printf("我已经成功建立了一个空表\n");
printf("下面录入图书信息(以n=-100表示结束)\n");
while(n!=-100)
{
printf("编号:\n");
scanf("%s",L.elem[g].no);
printf("名称:\n");
scanf("%s",L.elem[g].name);
printf("价格:\n");
scanf("%f",&L.elem[g].price);
g++;
++L.length;
printf("n=");
scanf("%d",&n);
}
}
else
{
printf("建立顺序表失败\n");
}
int door=1; //开关变量,1-->>开,2-->>关
int number; //功能编号
int i; //存放用户输入的查询,插入,删除位置的序号
do
{
printf("****************欢迎使用图书管理系统********************\n");
printf("** 输入1:按位置取值 **\n");
printf("** 输入2:查找元素在表中的序号 **\n");
printf("** 输入3:插入新的图书 **\n");
printf("** 输入4:删除表中的元素 **\n");
printf("** 输入5:输出所有的图书信息 **\n");
printf("** 输入0:退出 **\n");
printf("****************欢迎使用该功能模块**********************\n");
printf("你要执行的功能编号是:");
scanf("%d",&number);
switch(number)
{
case 1:
printf("输入你要查询的位置序号:\n");
scanf("%d",&i);
if(GetElem(L,i,e))
{
printf("%d位置上的图书信息为:\n",i);
printf("%s\t%s\t%f\n",e.no,e.name,e.price);
}
else
{
printf("位置序号不合法!\n");
}
break;
case 2:
printf("输入你要查询的书名:\n");
scanf("%s",ch);
LocateElem(L,ch);
if(LocateElem(L,ch)!=0)
{
printf("%s在表中的位置序号为:%d\n",ch,LocateElem(L,ch));
}
else
{
printf("%s不存在\n",ch);
}
break;
case 3:
printf("输入你要插入图书的位置序号:\n");
scanf("%d",&i);
printf("输入插入的图书的信息:\n");
printf("图书编号:");
scanf("%s",e.no);
printf("图书名称:");
scanf("%s",e.name);
printf("图书价格:");
scanf("%f",&e.price);
if(ListInsert(L,i,e))
{
printf("成功插入图书!\n");
}
else
{
printf("失败!\n");
}
break;
case 4:
printf("输入你要删除的图书的位置序号:\n");
scanf("%d",&i);
if(ListDelete(L,i)==1)
{
printf("删除成功!\n");
}
else
{
printf("失败!\n");
}
break;
case 5:
BookInformation(L);
break;
case 0:
door=0;
break;
default :
printf("无效输入,请重新输入\n");
}
}while(door==1);
printf("成功退出!\n");
return 0;
}
//创建空表
Status InitList(SqList &L)
{
L.elem=new Book[MAXSIZE]; //分配一个大小为 MAXSIZE的数组空间 ,类型为Book
if(!L.elem)
{
return OVERFLOW; //分配失败退出
}
L.length=0; //空表表长为0
return OK;
}
//按位置取值
Status GetElem(SqList &L,int i,Book &e)
{
//按位置取值,先检查位置序号i是否合理(1<=i<=length),不合理,就返回ERROR
//若合理,就把L.elem[i-1]元素赋值给参数e
if(i<1||i>L.length)
{
return ERROR;
}
e=L.elem[i-1];
return OK;
}
//按书名查找
Status LocateElem(SqList &L,char e[] )
{
//遍历数组,挨个查找
int i;
for(i=0;i<L.length;i++)
{
if(strcmp(L.elem[i].name,e)==0)
{
return i+1; //找到就返回位置序号
}
}
return 0; //查找失败,返回0
}
//插入
Status ListInsert(SqList &L,int i,Book e)
{
//检查位置i是否合法
if(i<1||i>L.length+1)
{
return ERROR; //i值不合法,返回ERROR
}
//检查表是否已满
if(L.length==MAXSIZE)
{
return ERROR; //当前存储空间已满
}
//将第n个至第i个位置上的元素后移,空出第i个位置
int j;
for(j=L.length-1;j>=i-1;j--)
{
L.elem[j+1]=L.elem[j];
}
//把元素e放在第i个位置上
strcpy(L.elem[i-1].no,e.no);
strcpy(L.elem[i-1].name,e.name);
L.elem[i-1].price=e.price;
//表长加1
++L.length;
return OK;
}
//删除
Status ListDelete(SqList &L,int i)
{
//检查是否为空表
if(L.length==0)
{
return ERROR; //空表返回ERROR
}
//检查位置i是否合法
if(i<1||i>L.length)
{
return ERROR; //不合法返回ERROR
}
//将第i至第n个位置上的元素前移,覆盖第i个位置上的元素
int j;
for(j=i;j<=L.length-1;j++)
{
L.elem[j-1]=L.elem[j];
}
//表长减1
--L.length;
return OK;
}
//输出所以的图书信息
Status BookInformation(SqList &L)
{
//检查是否为空表
if(L.length==0)
{
printf("你没有存入图书信息\n");
return ERROR;
}
//遍历数组
int j;
printf("\n\n*******************图书展示**********************\n\n");
for(j=0;j<L.length;j++)
{
printf("%s\t%s\t%f\n\n\n",L.elem[j].no,L.elem[j].name,L.elem[j].price);
}
return OK;
}