一、实验目的
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 LNode{
Student data; //存放学生信息的数据域
struct LNode *next; //指向下一个学生信息的指针域
}LNode,* linklist;
链表图解:
实验内容:
实验所使用头文件以及声明语句,其中length为全局变量
#include<iostream>
#include<string.h>
#include<fstream>
using namespace std;
int length=0;
链表的定义语句,lnode与*linklist为等价的:
注:typedef的相应知识这个大牛的文章讲得很清楚。
typedef struct{
string no;
string name;
char xb;
int age;
}student;
typedef struct lnode{
student data;
struct lnode *next;
}lnode,*linklist;
子菜单函数,提高程序的交互性
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;
}
子输入函数,在这个函数中我把输入子函数与创建头节点子函数结合在一个函数中了,链表中我没有使用文件输入的方式
void creat(linklist &l) {
l=new lnode;
l->next=NULL;
cout<<"创建链表头结点成功"<<endl;
linklist p,r;
int n,i;
r=l;
p=r->next;
cout<<"请输入学生数:"<<endl;
cin>>n;
cout<<"请输入学生学号 姓名 性别: "<<endl;
for(i=1;i<=n;i++){
p=new lnode;
cin>>p->data.no>>p->data.name>>p->data.xb>>p->data.age;
p->next=NULL;
r->next=p;
r=p;
length++;
}
cout<<"输入成功!"<<endl;
}
子输出函数,将链表中的每一个元素进行输出操作
void output(linklist l){
linklist p,r;
r=l;
cout<<"该表所有学生的学号 姓名 性别 年龄为:"<<endl;
while(r->next!=NULL){
p=r->next;
cout<<p->data.no<<" "<<p->data.name<<" "<<p->data.xb<<" "<<p->data.age<<endl;
r=p;
}
cout<<"输出成功!"<<endl;
}
子查找函数,根据输入的元素在链表中进行查找并输出,这在整个链表中是最为重要的一部分,可以说如果你掌握了查找那么剩下的功能你就都能实现了:
void search_1(linklist l){
string name;
linklist p,r;
r=l;
int i,flag=0;
cout<<"请输入要查找的学生姓名:"<<endl;
cin>>name;
while(r->next!=NULL){
p=r->next;
if(p->data.name==name){
cout<<"你所查找的学生学号 姓名 性别 年龄为:"<<endl;
cout<<p->data.no<<" "<<p->data.name<<" "<<p->data.xb<<" "<<p->data.age<<endl;;
flag=1;
break;
}
else{
r=p;
}
}
if(flag==0){
cout<<"未查询到该学生信息!"<<endl;
}
else{
cout<<"查询成功!"<<endl;
}
}
void search_2(linklist l){
int i,n;
linklist p,r;
r=l;
cout<<"请输入要查询的学生位置:"<<endl;
cin>>n;
if(n<=0||n>length){
cout<<"查询错误!"<<endl;
}
else {
for(i=1;i<=n;i++){
p=r->next;
r=p;
}
cout<<"你所查找的学生学号 姓名 性别 年龄为:"<<endl;
cout<<p->data.no<<" "<<p->data.name<<" "<<p->data.xb<<" "<<p->data.age<<endl;
cout<<"查询成功!"<<endl;
}
}
子插入函数,链表的插入操作比起顺序表简单了许多,不需要频繁的移动大量元素,只需要改变指针的指向即可
void insert (linklist &l){
int n,i;
linklist p,r,e;
r=l;
e=new lnode;
cout<<"请输入插入的位置:"<<endl;
cin>>n;
if(n>length+1){
cout<<"插入错误!"<<endl;
}
else{
cout<<"请输入插入的学生学号 姓名 性别 年龄:"<<endl;
cin>>e->data.no>>e->data.name>>e->data.xb>>e->data.age;
for(i=1;i<n;i++){
p=r->next;
r=p;
}
e->next=p->next;
p->next=e;
cout<<"插入成功!"<<endl;
length++;
}
}
子删除函数,同插入函数,只需改变指针的指向即可
注:delete函数为释放new函数所申请的空间,与free的作用相似,涉及到动态分配的内容,这两个大牛的文章都讲的蛮清楚的
void delete_1(linklist &l){
int n,i;
linklist p,r;
r=l;
cout<<"请输入要删除的学生位置:"<<endl;
cin>>n;
for(i=1;i<n;i++){
r=r->next;
}
if(!(r->next)||n>length){
cout<<"删除错误!"<<endl;
}
else{
p=r->next;
r->next=p->next;
delete p;
length--;
}
}
子函数,主要功能即为将全局变量length输出,因此在进行插入删除操作时要主要看length的变化,即链长的变化
void lengthcout(linklist l){
cout<<"该表共有"<<length<<"位学生"<<endl<<"输出完成!"<<endl;;
}
主函数,为了减少代码复杂度我将子函数的返回值全设为了void:
int main(){
int choose,i;
linklist l;
menu();
cout<<"请输入操作选择"<<endl;
cin>>choose;
while(choose){
switch(choose){
case 1:creat(l);break;
case 2:output(l);break;
case 3:search_1(l);break;
case 4:search_2(l);break;
case 5:insert(l);break;
case 6:delete_1(l);break;
case 7:lengthcout(l);break;
}
cout<<"请输入操作"<<endl;
cin>>choose;
}
cout<<"欢迎下次使用"<<endl;
}
注:同顺序表,&l,*l,与l的使用条件是不同的,要注意区分,关于这部分内容这个大牛的文章讲的很清楚
链表的使用最重要的就是在脑海中构建一个链表,明确指针域的指向就可以很清楚的写出程序了!