1.1 实验目的
通过实验达到⑴加深对线性表的概念、基本运算的理解;⑵熟练掌握线性表的逻辑结构与物理结构的关系;⑶物理结构采用顺序表,熟练掌握线性表的基本运算的实现。
1.2 线性表基本运算定义
依据最小完备性和常用性相结合的原则,以函数形式定义了线性表的初始化表、销毁表、清空表、判定空表、求表长和获得元素等12种基本运算,具体运算功能定义如下。
⑴初始化表:函数名称是InitaList(L);初始条件是线性表L不存在已存在;操作结果是构造一个空的线性表。
⑵销毁表:函数名称是DestroyList(L);初始条件是线性表L已存在;操作结果是销毁线性表L。
⑶清空表:函数名称是ClearList(L);初始条件是线性表L已存在;操作结果是将L重置为空表。
⑷判定空表:函数名称是ListEmpty(L);初始条件是线性表L已存在;操作结果是若L为空表则返回TRUE,否则返回FALSE。
⑸求表长:函数名称是ListLength(L);初始条件是线性表已存在;操作结果是返回L中数据元素的个数。
⑹获得元素:函数名称是GetElem(L,i,e);初始条件是线性表已存在,1≤i≤ListLength(L);操作结果是用e返回L中第i个数据元素的值。
⑺查找元素:函数名称是LocateElem(L,e,compare());初始条件是线性表已存在;操作结果是返回L中第1个与e满足关系compare()关系的数据元素的位序,若这样的数据元素不存在,则返回值为0。
⑻获得前驱:函数名称是PriorElem(L,cur_e,pre_e);初始条件是线性表L已存在;操作结果是若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。
⑼获得后继:函数名称是NextElem(L,cur_e,next_e);初始条件是线性表L已存在;操作结果是若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无定义。
⑽插入元素:函数名称是ListInsert(L,i,e);初始条件是线性表L已存在且非空,1≤i≤ListLength(L)+1;操作结果是在L的第i个位置之前插入新的数据元素e。
⑾删除元素:函数名称是ListDelete(L,i,e);初始条件是线性表L已存在且非空,1≤i≤ListLength(L);操作结果:删除L的第i个数据元素,用e返回其值。
⑿遍历表:函数名称是ListTraverse(L,visit()),初始条件是线性表L已存在;操作结果是依次对L的每个数据元素调用函数visit()。
1.3 实验任务
采用顺序表作为线性表的物理结构,实现§1.2的基本运算。其中ElemType为数据元素的类型名,具体含义可自行定义,其它有关类型和常量的定义和引用详见文献[1]的p10。
要求构造一个具有菜单的功能演示系统。其中,在主程序中完成函数调用所需实参值的准备和函数执行结果的显示,并给出适当的操作提示显示。附录A提供了简易菜单的框架。
演示系统可选择实现线性表的文件形式保存。其中,①需要设计文件数据记录格式,以高效保存线性表数据逻辑结构(D,{R})的完整信息;②需要设计线性表文件保存和加载操作合理模式。附录B提供了文件存取的方法。
演示系统可选择实现多个线性表管理。
源程序应按照代码规范增加注释和排版,目标程序务必是可以独立于IDE运行的EXE文件。
按照公告的时间及时提交电子档实验资料,所有资料存储于每位同学自己的相应文件夹下,其文件夹名称格式为“专业班级-学号姓名-n”。如:IS1402-U201414999李某某-n。其中,n表示第n次实验报告。
资料至少包括实验报告、实验源程序和实验目标程序。根据需要还可以增加测试用例文件等等。
附录A 顺序表实现框架程序清单
/* Linear Table On Sequence Structure */
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
/*---------page 10 on textbook ---------*/
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASTABLE -1
#define OVERFLOW -2
typedef int status;
typedef int ElemType; //数据元素类型定义
/*-------page 22 on textbook -------*/
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef struct{ //顺序表(顺序结构)的定义
ElemType * elem;
int length;
int listsize;
}SqList;
/*-----page 19 on textbook ---------*/
status IntiaList(SqList & L);
//status DestroyList(SqList & L);
//status ClearList(SqList &L);
//status ListEmpty(SqList L);
//int ListLength(SqList L);
//status GetElem(SqList L,int i,ElemType & e);
//status LocateElem(SqList L,ElemType e); //简化过
//status PriorElem(SqList L,ElemType cur,ElemType & pre_e);
//status NextElem(SqList L,ElemType cur,ElemType & next_e);
//status ListInsert(SqList & L,int i,ElemType e);
status ListDelete(SqList & L,int i,ElemType & e);
status ListTrabverse(SqList L); //简化过
/*--------------------------------------------*/
void main(void){
SqList L; int op=1;
while(op){
system("cls"); printf("\n\n");
printf(" Menu for Linear Table On Sequence Structure \n");
printf("-------------------------------------------------\n");
printf(" 1. IntiaList 7. LocateElem\n");
printf(" 2. DestroyList 8. PriorElem\n");
printf(" 3. ClearList 9. NextElem \n");
printf(" 4. ListEmpty 10. ListInsert\n");
printf(" 5. ListLength 11. ListDelete\n");
printf(" 6. GetElem 12. ListTrabverse\n");
printf(" 0. Exit\n");
printf("-------------------------------------------------\n");
printf(" 请选择你的操作[0~12]:");
scanf("%d",&op);
switch(op){
case 1:
//printf("\n----IntiaList功能待实现!\n");
if(IntiaList(L)==OK) printf("线性表创建成功!\n");
else printf("线性表创建失败!\n");
getchar();getchar();
break;
case 2:
printf("\n----DestroyList功能待实现!\n");
getchar();getchar();
break;
case 3:
printf("\n----ClearList功能待实现!\n");
getchar();getchar();
break;
case 4:
printf("\n----ListEmpty功能待实现!\n");
getchar();getchar();
break;
case 5:
printf("\n----ListLength功能待实现!\n");
getchar();getchar();
break;
case 6:
printf("\n----GetElem功能待实现!\n");
getchar();getchar();
break;
case 7:
printf("\n----LocateElem功能待实现!\n");
getchar();getchar();
break;
case 8:
printf("\n----PriorElem功能待实现!\n");
getchar();getchar();
break;
case 9:
printf("\n----NextElem功能待实现!\n");
getchar();getchar();
break;
case 10:
printf("\n----ListInsert功能待实现!\n");
getchar();getchar();
break;
case 11:
printf("\n----ListDelete功能待实现!\n");
getchar();getchar();
break;
case 12:
//printf("\n----ListTrabverse功能待实现!\n");
if(!ListTrabverse(L)) printf("线性表是空表!\n");
getchar();getchar();
break;
case 0:
break;
}//end of switch
}//end of while
printf("欢迎下次再使用本系统!\n");
}//end of main()
/*--------page 23 on textbook --------------------*/
status IntiaList(SqList & L){
L.elem = (ElemType *)malloc( LIST_INIT_SIZE * sizeof (ElemType));
if(!L.elem) exit(OVERFLOW);
L.length=0;
L.listsize=LIST_INIT_SIZE;
return OK;
}
status ListTrabverse(SqList L){
int i;
printf("\n-----------all elements -----------------------\n");
for(i=0;i<L.length;i++) printf("%d ",L.elem[i]);
printf("\n------------------ end ------------------------\n");
return L.length;
}
附录B 数据元素的文件读写
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char c; int d; float f;
} ElemType;
typedef struct {
ElemType elem[10]; int length;
} SqList;
SqList L={{{'a',1,1.1},{'b',2,2.2},{'c',3,3.3},{'d',4,4.4}}, 4};
int main(int argc, char *argv[]) {
FILE *fp; char filename[30]; int i;
printf("input file name: ");
scanf("%s",filename);
//写文件的方法
if ((fp=fopen(filename,"w"))==NULL)
{
printf("File open erroe\n ");
return 1;
}
fwrite(L.elem,sizeof(ElemType),L.length,fp);
//这里是1次性写入,对于其它物理结构,可通过遍历,逐个访问数据元素
//并写入到文件中
fclose(fp);
//读文件的方法
L.length=0;
if ((fp=fopen(filename,"r"))==NULL)
{
printf("File open erroe\n ");
return 1;
}
while(fread(&L.elem[L.length],sizeof(ElemType),1,fp))
L.length++;
//这里从文件中逐个读取数据元素恢复顺序表,对于不同的物理结构,可通过读//取的数据元素恢复内存中的物理结构。
fclose(fp);
return 0;
}
* Linear Table On Sequence Structure */
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include<string.h>
/*---------page 10 on textbook ---------*/
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASTABLE -1
#define OVERFLOW -2
typedef int status;
typedef int ElemType; //数据元素类型定义
/*-------page 22 on textbook -------*/
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef struct{ //顺序表(顺序结构)的定义
ElemType * elem;
int length;
int listsize;
char name[10];
}SqList;
/*-----page 19 on textbook ---------*/
status InitiaList(SqList &L); //初始化表
status DestroyList(SqList &L);//销毁表
status ClearList(SqList &L);//置空表
status ListEmpty(SqList L);//检查是否为空
int ListLength(SqList L);//计算表长
status GetElem(SqList L,int i,ElemType & e);//获取元素
status LocateElem(SqList L,ElemType e); //定位
status PriorElem(SqList L,ElemType cur,ElemType & pre_e)//获取前驱;
status NextElem(SqList L,ElemType cur,ElemType & next_e);//获取后继
status ListInsert(SqList &L,int i,ElemType e);//插入元素
status ListDelete(SqList &L,int i,ElemType & e);//删除元素
status ListTrabverse(SqList L); //遍历线性表
status OpenFile(SqList &L);//读取文件
status SaveFile(SqList &L);//保存文件
int find(SqList lists[],SqList **L);//在线性表数组中查找线性表,找到返回在数组中的位置,并用L指向找到的线性表,没找到返回0
void SetValue(SqList &L); //给顺序表手动赋值函数
int listnum=0; //全局变量,记录当前线性表数组中线性表个数
/*--------------------------------------------*/
int main(void){
SqList lists[10];//定义一个线性表数组便于管理多个线性表
SqList* L; //定义一个指针L用于指向所要进行操作的线性表
int op=1;
while(op){ //简易菜单
system("cls"); printf("\n\n");
printf(" Menu for Linear Table On Sequence Structure \n");
printf("-------------------------------------------------\n");
printf(" 1. IntiaList 7. LocateElem\n");
printf(" 2. DestroyList 8. PriorElem\n");
printf(" 3. ClearList 9. NextElem \n");
printf(" 4. ListEmpty 10. ListInsert\n");
printf(" 5. ListLength 11. ListDelete\n");
printf(" 6. GetElem 12. ListTrabverse\n");
printf(" 13.SaveFile 14 LinearList\n");
printf(" 0. Exit\n");
printf("-------------------------------------------------\n");
printf(" 请选择你的操作[0~12]:");
scanf("%d",&op);
getchar();
switch(op){
case 1:
//printf("\n----IntiaList功能待实现!\n");
if(InitiaList(lists[listnum])==OK) {
listnum++; //创建成功后计数器加一
printf("线性表创建成功!请对线性表进行命名:");
scanf("%s",lists[listnum-1].name);}
else {
printf("线性表创建失败!\n");
break;}
printf("请选择:1.请对线性表进行键盘赋值\n 2.读取文件\n");
int k;
lists[listnum-1];
scanf("%d",&k);
getchar();
switch(k){
case 1: SetValue(lists[listnum-1]); //选择读取文件或者键盘赋值
break;
case 2: if(!OpenFile(lists[listnum-1]))
listnum--; //此处若打开文件失败则删除所创建得线性表
break;
}
getchar();
break;
case 2:
int y;
y=find(lists,&L); //因为此处销毁链表需用到该线性表在数组中的位置故用一个变量接受返回值
if(!y)
break;
if(DestroyList(*L))
{
for(int i=y-1;i<listnum-1;i++) //从数组中删除销毁得线性表
lists[i]=lists[i+1];
printf("线性表销毁成功!\n");
listnum--;
}
else
printf("线性表不存在,操作失败\n");
getchar();
break;
case 3:
if(!find(lists,&L))
break;
if(ClearList(*L))
printf("线性表重置为空表成功\n");
else
printf("线性表不存在,操作失败\n");
getchar();
break;
case 4:
if(!find(lists,&L))
break;
if(!(*L).elem)
printf("线性表不存在,操作失败\n");
else
if(ListEmpty(*L))
printf("该线性表是空表\n");
else
printf("该线性表不是空表\n");
getchar();
break;
case 5:
if(!find(lists,&L))
break;
if(!(*L).elem)
printf("操作失败,不存在该线性表");
else
printf("该线性表的长度为%d",ListLength(*L));
getchar();
break;
case 6:
if(!find(lists,&L))
break;
if(!(*L).length){
printf("对不起,该表是空表");
getchar();
break;}
printf("您想查找该线性表的第几个元素:\n");
int i;
scanf("%d",&i);
getchar();
if(!(i>0&&i<=(*L).length))
printf("输入有误或者超过了该表的长度,操作失败\n");
else{
ElemType e;
GetElem(*L,i,e);
printf("操作成功,第%d个元素值为%d\n",i,e);
}
getchar();
break;
case 7:
if(!find(lists,&L))
break;
if(!(*L).length){
printf("对不起,该表是空表");
getchar();
break;}
printf("请输入要比较的值e:");
ElemType e;
scanf("%d",&e);
getchar();
if(!(*L).elem)
printf("线性表不存在,操作失败\n");
else
int i;
if(i=LocateElem(*L,e))
printf("该线性表第%d个元素与e相等!\n",i);
else
printf("该线性表不存在与e相等的元素");
getchar();
break;
case 8:
if(!find(lists,&L))
break;
if(!(*L).length){
printf("对不起,该表是空表");
getchar();
break;}
printf("你想获得哪个元素的前驱;\n");
ElemType cur_e;
scanf("%d",&cur_e);
getchar();
ElemType pre_e;
if(PriorElem(*L,cur_e,pre_e))
printf("它的前驱为%d\n",pre_e);
else
printf("该元素不存在或者该元素不存在前驱\n");
getchar();
break;
case 9:
if(!find(lists,&L))
break;
if(!(*L).length){
printf("对不起,该表是空表");
getchar();
break;}
printf("你想获得哪个元素的后继;\n");
ElemType cur1_e;
scanf("%d",&cur1_e);
getchar();
ElemType next_e;
if(NextElem(*L,cur1_e,next_e))
printf("它的后继为%d\n",next_e);
else
printf("该元素不存在或者该元素不存在后继\n");
getchar();
break;
case 10:
if(!find(lists,&L))
break;
if(!((*L).length)){
printf("对不起,该表是空表");
getchar();
break;}
printf("请输入你要插入的位置和元素值:");
int i1;
ElemType e1;
scanf("%d%d",&i1,&e1);
getchar();
if(ListInsert(*L,i1,e1))
printf("操作成功,在第%d个元素前插入了%d\n",i1,e1);
else
printf("线性表不存在,操作失败\n");
getchar();
break;
case 11:
if(!find(lists,&L))
break;
if(!(*L).length){
printf("对不起,该表是空表");
getchar();
break;}
printf("请输入你要删除的元素的位置:\n");
int i2;
ElemType e2;
scanf("%d",&i2);
getchar();
if(ListDelete(*L,i2,e2))
printf("操作成功,删除了第%d个元素,该元素原来的值为%d\n",i2,e2);
else
printf("线性表不存在或者输入错误,操作失败");
getchar();
break;
case 12:
if(!find(lists,&L))
break;
//printf("\n----ListTrabverse功能待实现!\n");
if(!ListTrabverse(*L)) printf("线性表是空表!\n");
getchar();
break;
case 13:
if(!find(lists,&L))
break;
SaveFile(*L);
getchar();
case 14:
printf("当前内存中有以下几个线性表\n");
for(int i=0;i<listnum;i++)
printf("%s ",lists[i].name);
getchar();
case 0:
break;
}//end of switch
}//end of while
printf("欢迎下次再使用本系统!\n");
}//end of main()
/*--------page 23 on textbook --------------------*/
status InitiaList(SqList & L){
L.elem = (ElemType *)malloc( LIST_INIT_SIZE * sizeof (ElemType));
if(!L.elem) exit(OVERFLOW);
L.length=0;
L.listsize=LIST_INIT_SIZE;
return OK;
}
status DestroyList(SqList & L){
if(L.elem==NULL)
return ERROR;
free(L.elem);
L.length=0;
L.listsize=LIST_INIT_SIZE;
return OK;
}
status ClearList(SqList &L){
if(L.elem==NULL) //表不存在则失败
return ERROR;
L.length=0;
L.listsize=LIST_INIT_SIZE;//重置表
return OK;
}
status ListEmpty(SqList L){
if(!L.elem)
return TRUE;
if(!L.length) //长度为0则是空表
return TRUE;
return FALSE;
}
int ListLength(SqList L){
if(!L.elem)
return ERROR;
return L.length; //返回长度
}
status GetElem(SqList L,int i,ElemType & e){
if(!L.elem)
return ERROR;
e=L.elem[i-1]; //获取元素
return OK;
}
status LocateElem(SqList L,ElemType e){
if(!L.elem)
return ERROR;
for(int i=0;i<L.length;i++)
if(L.elem[i]==e) //查找与e相等的元素
return i+1;
return 0;
}
status PriorElem(SqList L,ElemType cur,ElemType & pre_e){
if(!L.elem||cur==L.elem[0])
return ERROR;
for(int i=1;i<L.length;i++)
if(L.elem[i]==cur)
{
pre_e=L.elem[i-1];
return OK;}
return ERROR;
}
status NextElem(SqList L,ElemType cur,ElemType & next_e){
if(!L.elem||cur==L.elem[L.length-1])
return ERROR;
for(int i=0;i<L.length-1;i++)
if(L.elem[i]==cur){
next_e=L.elem[i+1];
return OK;
}
return ERROR;
}
status ListInsert(SqList & L,int i,ElemType e){
if(!L.elem||!L.length)
return ERROR;
if(L.length>=L.listsize)
{
ElemType* newbase;
newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase)
exit(OVERFLOW);
L.elem=newbase;
L.listsize+=LISTINCREMENT;
}
for(int j=L.length;j>=i;j--)
L.elem[j]=L.elem[j-1];
L.elem[i-1]=e;
L.length++;
return OK;
}
status ListDelete(SqList & L,int i,ElemType & e){
if(!L.elem||!L.length||i>=L.length||i<=0)
return ERROR;
e=L.elem[i-1];
for(int j=i;j<L.length;j++)
L.elem[j-1]=L.elem[j];
L.length--;
return OK;
}
status ListTrabverse(SqList L){
int i;
printf("\n-----------all elements -----------------------\n");
for(i=0;i<L.length;i++) printf("%d ",L.elem[i]);
printf("\n------------------ end ------------------------\n");
return L.length;
}
status OpenFile(SqList &L){
FILE* fp;
char filename[20];
printf("请输入文件名:");
scanf("%s",filename);
fp=fopen(filename,"r");
if(!fp){
printf("打开文件失败");
getchar();
return ERROR;}
while(fread(&L.elem[L.length],sizeof(ElemType),1,fp))
L.length++;
printf("打开文件成功");
fclose(fp);
getchar();
return OK;
}
status SaveFile(SqList &L)
{
FILE* fp1;
char filename1[20];
printf("请输入文件名:");
scanf("%s",filename1);
getchar();
if ((fp1=fopen(filename1,"w"))==NULL)
{
printf("File open erroe\n ");
getchar();
return ERROR;
}
fwrite(L.elem,sizeof(ElemType),L.length,fp1);
//这里是1次性写入,对于其它物理结构,可通过遍历,逐个访问数据元素
//并写入到文件中
fclose(fp1);
printf("保存成功");
return OK;
}
void SetValue(SqList &L){
printf("请输入元素值并以Ctrl+Z结束\n") ;
for(int m=0;;m++)
{
if(m>=L.listsize) //当容量不够时,扩大容量
{
ElemType* newbase;
newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase)
exit(OVERFLOW);
L.elem=newbase;
L.listsize+=LISTINCREMENT;
}
if((scanf("%d",&L.elem[m])==EOF)) //当遇到结束标志时跳出赋值循环
break;
L.length++;
}
printf("赋值成功!\n"); //提示赋值成功
}
int find(SqList lists[],SqList ** L) //找到返回在数组中的位置,
{
printf("请选择要进行操作的线性表的名字:");
char name[10];
scanf("%s",name);
for(int flag=0;flag<listnum;flag++)
{
if(!strcmp(lists[flag].name,name))
{
*L=&lists[flag];
printf("找到了!");
getchar();
return flag+1 ;
}
}
printf("没找到");
getchar();
getchar();
return ERROR;
}
代码中创建一个线性表数组对多个线性表进行管理可以完善为用一个顺序表结构,顺序表结构成员变量有三个:表长,表容量,以及顺序表中的头元素的指针
这个顺序表中得元素为所要进行管理得线性表(顺序表);
具体代码:
typdef struct{
int length;
int listsize;
SqList* pL;}Lists;
然后在执行过程中可以用预编译语句重定义TypeElem为 SqList ,这样可以直接调用所定义的对线性表相关操作 的函数对这个新的线性表进行关了,非常方便,也体现了对线性表操作的函数的通用性。