一、实验目的
1.掌握线性表的定义;
2.掌握线性表的顺序存储基本操作,如建立、查找、插入和删除等。
二、实验内容
定义一个包含学生信息(学号,姓名,性别,年龄)的的顺序表,使其具有如下功能:
(1) 根据指定学生个数,逐个输入学生信息;
(2) 逐个显示学生表中所有学生的相关信息;
(3) 根据姓名进行查找,返回此学生的学生信息;
(4) 根据指定的位置可返回相应的学生信息;
(5) 给定一个学生信息,插入到表中指定的位置;
(6) 删除指定位置的学生记录;
(7) 统计表中学生个数。
三、实验提示
学生信息的定义:
typedef struct {
char no[11]; //表示11位学号,也可以定义为string no;
char name[20]; //表示姓名,也可以定义为string name;
char xb; //表示性别,以字母M表示男,字母W表示女
int age; //表示年龄
} Student;
顺序表的定义
typedef struct {
Student *elem; //指向线性表的基地址
int length; //线性表的当前长度
}SqList;
包含的头文件与声明:
#include<iostream>
#include<string.h>
#include<fstream>
using namespace std;
#define maxsize 100
对顺序表进行定义:
typedef struct{
string no;
string name;
char xb;
int age;
}student;
typedef struct{
student *elem;
int length;
}sqlist;
子函数,为顺序表分配空间:
注:在C语言中动态分配的函数有malloc、calloc和realloc,包含在头文件<stdio.h>中,C++则是简单的new函数,其中的区别我们将在下一节进行讲明;
void initlist(sqlist &l){
l.elem=new student[maxsize];
if (!l.elem)
cout<<"创建顺序表失败"<<endl;
else{
l.length = 0;
cout<<"创建顺序表成功"<<endl;
}
}
子菜单函数,用于提高程序的交互性:
void menu(){
cout<<"1.输入学生信息"<<endl;
cout<<"2.显示所有学生信息"<<endl;
cout<<"3.根据姓名查找学生信息"<<endl;
cout<<"4.根据指定位置学生信息"<<endl;
cout<<"5.插入学生信息"<<endl;
cout<<"6.删除指定学生信息"<<endl;
cout<<"7.统计学生个数"<<endl;
cout<<"0.退出"<<endl;
}
子输入函数,在代码段中我使用了两种输入的方式,一种为文件的输入,被注释的部分则为一般的正常逐个输入:
注:在c++中我们输入输出通常使用cin与cout函数,相比之下比c语言的scanf与printf更节省时间
void input(sqlist &l){
int i=0;
fstream file;//文件输入
file.open("student.txt");
if(!file){
cout<<"错误!未找到文件"<<endl;
}
while(!file.eof()){
file>>l.elem[i].no>>l.elem[i].name>>l.elem[i].xb>>l.elem[i].age;
i++;
}
cout<<"输入student.txt信息完毕"<<endl;
l.length=i;//不用减一,i从开始加
file.close();//文件关闭
// int n;
// cout<<"请输入学生个数"<<endl;
// cin>>n;
// cout<<"请输入学生的 学号 姓名 性别 年龄:"<<endl;
// for(int i=l.length;i<=n-1;i++){
// cin>>l.elem[i].no>>l.elem[i].name>>l.elem[i].xb>>l.elem[i].age;
// }
// l.length=n;
}
功能子函数执行将顺序表中的元素全部逐个输出:
void output(sqlist l){
cout<<"表中所有学生学号 姓名 性别 年龄为:"<<endl;
for(int i=0;i<=l.length-1;i++){
cout<<l.elem[i].no<<" "<<l.elem[i].name<<" "<<l.elem[i].xb<<" "<<l.elem[i].age<<endl;
}
}
子查询函数,主要功能为根据学生姓名或位置进行查找并输出:
void search(sqlist l){
string name;
int flag=0;
cout<<"请输入要查询的学生姓名:"<<endl;
cin>>name;
for(int i=0;i<=l.length-1;i++){
if(l.elem[i].name==name){
cout<<"该生的学号 姓名 性别 年龄为:"<<endl;
cout<<l.elem[i].no<<" "<<l.elem[i].name<<" "<<l.elem[i].xb<<" "<<l.elem[i].age<<endl;
flag=1;
}
}
if(!flag){
cout<<"未查询到学生"<<name<<"的信息"<<endl;
}
}
void search_2(sqlist l){
int i;
cout<<"请输入要查询学生的位置"<<endl;
cin>>i;
if(i<=0||i>=l.length){
cout<<"未查询到该学生信息"<<endl;
}
else{
cout<<"该生的学号 姓名 性别 年龄为:"<<endl;
cout<<l.elem[i-1].no<<" "<<l.elem[i-1].name<<" "<<l.elem[i-1].xb<<" "<<l.elem[i-1].age<<endl;
}
}
子插入函数,功能为在相应位置进行插入操作,主要实现将该位置的及以后的元素全部向后移动一位,所以需要判断表是否已满。因为顺序表插入与删除操作都需要大量的时间复杂度所以在需要大量更改元素的情况下,我们大多使用链表来完成实验:
void insert(sqlist &l){
int n,i;
cout<<"请输入要插入的学生位置"<<endl;
cin>>n;
if(n<=0||n>=maxsize||l.length>=maxsize){
cout<<"插入错误"<<endl;
}
else{
for(i=l.length-1;i>=n-1;i--){//减一
l.elem[i+1].no=l.elem[i].no;
l.elem[i+1].name=l.elem[i].name;
l.elem[i+1].xb=l.elem[i].xb;
l.elem[i+1].age=l.elem[i].age;
}
cout<<"请输入要插入学生的学号 姓名 性别 年龄:"<<endl;
cin>>l.elem[n-1].no>>l.elem[n-1].name>>l.elem[n-1].xb>>l.elem[n-1].age;
l.length+=1;//插入后长度加一
cout<<"插入成功"<<endl;
}
}
注:该代码段中的l.elem[i+1].n=l.elem[i].no以及其他元素的替换可以统合为l.elem[i+1]=l.elem[i],所实现的功能是一样的,可以减少代码长度
子删除函数,主要功能为将指定位置的函数进行删除:
注:在C++中delete函数用于回收new分配的内存空间,包含在头文件<iostream>中。C++中我们在回收用 new 分配的单个对象的内存空间的时候用delete,回收用 new[]分配的一组对象的内存空间的时候用delete[]。所以我使用的函数名为delete_1
void delete_1(sqlist &l){
int n,i;
cout<<"请输入要删除的学生位置"<<endl;
cin>>n;
if(n<=0||n>l.length){
cout<<"删除错误"<<endl;
}
else{
for(i=n;i<=l.length-1;i++){//减一
l.elem[i-1].no=l.elem[i].no;
l.elem[i-1].name=l.elem[i].name;
l.elem[i-1].xb=l.elem[i].xb;
l.elem[i-1].age=l.elem[i].age;
}
cout<<"删除成功"<<endl;
l.length-=1;//删除后长度减一
}
}
子输出函数,实现的功能为将表中含有的学生人数输出,即为输出l.length,因此我们在进行插入与删除操作时应注意l.length长度的变化:
void list(sqlist l){
cout<<"表中共有"<<l.length<<"名学生"<<endl;
}
主函数,主要用到的为while语句与switch语句,为了减少操作难度与代码简洁我将所有的函数返回值设置为void空类型,所有操作均在子函数中进行:
int main(){
sqlist l;
int i = 0, n, temp,choose;
initlist(l);
menu();
cin>>choose;
while(choose!=0){
switch(choose){
case 1:input(l);break;
case 2:output(l);break;
case 3:search(l);break;
case 4:search_2(l);break;
case 5:insert(l);break;
case 6:delete_1(l);break;
case 7:list(l);break;
}
cout<<"请输入操作"<<endl;
cin>>choose;
}
cout<<"欢迎下次使用"endl;
return 0;
}
文件截图:
注:如图,我们在使用文件输入的时候要记得将文件名改为代码中打开的文件名如"student.txt"并在另存为时将编码改为ANSI,否则会出现文件输入时文字乱码
注:目前程序还存在一些bug,例如在我输入5位学生信息时,若是在插入时不小心插入到第7位,在执行输出函数时,第6位的值变成了0,而插入第7位学生的信息却会消失或者被覆盖;
以下为该程序的运行结果: