学生管理系统(C++,控制台,文件读取,姓名排序)
这是一个用C++写的控制台程序,利用简单的菜单实现学生信息的管理。
简图如下所示:
菜单栏:
查询数据:
修改数据:
打印数据:
以下是添加了一些学生信息的进行一些操作的结果:
除了上面所展示的功能以外,还可以将所有的学生信息保存到一个txt文件中,或者将一个文件里面的学生信息读取进来,当然,读取的文件需要按照保存文件的格式进行排列。
在刚开始的时候我认为中文排序是最困难的,在经过很多网上资料的翻阅之后,终于找到了一个可行的方法。你可以百度一下pinyin.c了解一下这种中文排序的方法,这个文件里面是一个char类型的数组,有人将unicode码中从小到大的所有中文汉字的首字母依次存储到这个数组中,这意味着我们只需要获取这个中文汉字的unicode码就可以得到它的首字母,此时你就使用排序算法对字母转化而来的数值(ASCII码)进行排序就好了。由于我们平时使用的保存姓名都是用的字符串string类型,需要获得unicode码,还需要将它转化为wstring类型之后才能获取,这里我直接找到了一个函数将它转化。
下面我们还是来查看一下源代码:我是使用单链表实现的,不仅实现了一个链表类,该类还包含了一个简单的结构——节点。总有有三个文件
**⒈Linked_List.h **
#ifndef LINKED_LIST
#define LINKED_LIST
#include<iostream>
#include<iomanip>
#include<string>
#include <cstdlib>
#include<fstream>
using namespace std;
#define HANZI_START 19968 //unicode码的中文汉字起始位置就是19968
#define HANZI_COUNT 20902 //unicode码中包含了20902个中文汉字,所以需要这么大一个数组才能存储它们所有的首字母
wstring String_To_WString(const string &s); //将string转化为wstring类型
int Get_First_Pinyin(string name); //从数组中提取中文汉字的首字母
struct Node //保存学生信息的一个节点
{
string Name; //姓名
int Student_ID; //学号
string Gender; //性别
int Age; //年龄
string Class; //班级
string Health_Status; //健康状况
Node *Next_Student; //指向下一个节点的指针
Node() //默认构造函数,实现成员的初始化
{
Name = "NULL";
Student_ID = NULL;
Gender = "NULL";
Age = NULL;
Class = "NULL";
Health_Status = " NULL";
Next_Student = NULL;
}
Node(string name) //利用姓名创建学生信息的构造函数
{
Name = name;
cout << "请输入"<<name<<"的学号:";
cin >> Student_ID;
cout << "请输入" << name << "的性别:";
cin >> Gender;
cout << "请输入" << name << "的年龄:";
cin >> Age;
cout << "请输入" << name << "的班级:";
cin >>Class;
cout << "请输入" << name << "健康状况:";
cin >> Health_Status;
Next_Student = NULL;
}
Node(string name,int student_id,string gender,int age,string Class,string health_status)
{ //传入所有信息,直接创建一个学生信息
Name = name;
Student_ID = student_id;
Gender = gender;
Age = age;
this->Class = Class;
Health_Status = health_status;
Next_Student = NULL;
}
};
class Linked_List //单链表类
{
int Student_Count; //学生人数
Node *Head_Point; //头节点,不存储学生信息
public:
static bool Is_Previous; //在查询,删除或者修改等操作中,我们需要得到一个指向我们想要操作的节点的指针,如果是查询或者修改,我们需要指向当前学生;如果是删除,我们就需要指向被删除学生的前一个学生。
Linked_List()
{
Node *p = new Node; //当我们新建一个单链表对象的时候,我们应该为它创建一个头节点,并完成该类的成员初始化工作。
this->Head_Point =p;
Head_Point->Next_Student= NULL;
Student_Count = 0;
}
~Linked_List() //析构函数
{
}
Linked_List(const Linked_List &list); //拷贝构造函数
Linked_List& operator=(const Linked_List &list); //赋值构造函数
void Clear_Linked_List(); //销毁链表
void Print_Student_Details(string name); //利用学生姓名打印学生信息
void Print_Student_Details(int studeng_id); //利用学生学号打印学生信息
Node* Find_Name(string name); //利用学生姓名找到学生,并返回指向该学生的指针
Node* Find_Student_Id(int studeng_id); //利用学生学号找到学生,并返回指向该学生的指针
void Edit_Student(); //该函数可以修改学生信息,通过查找到学生姓名来进行修改
void Student_Id_Sort();//学号大小来排序,使用冒泡排序法
void Student_Name_Sort(); //对每一个名字的姓进行排序
void Delete_Student(); //删除学生信息,利用姓名查找并删除
void Print_Every_Student(); //打印所有学生的信息
//这两个保存和读取的函数并没有添加到菜单栏中,这两个函数是在我写好这个类之后过了好久才写的,也懒得去改动菜单栏了,但是我测试过是可行的。
void Write_Every_Student_TXT() //保存所有学生信息到文件中
{
ofstream fout("H:\\Visual Studio 2015\\My projects\\Linked_List\\Linked_List\\Student.txt");
//保存到该文件目录下的文件,如果没有该文件,将会创建该文件,有的话,会清空原有文件中的所有内容
Node *p = Head_Point;
if (!fout.is_open()) //如果文件创建失败,就返回不进行后续操作
{
cout << "文件创建失败!!!";
return;
}
fout << "姓名" << " 学号" << " 性别" << " 年龄" << " 班级" << " 健康状况" << endl;
for (int i = 1; i <= Student_Count; i++)
{ //利用左对齐,填充字符控制格式化的输出到文件
p = p->Next_Student;
fout << left << setw(15) << setfill(' ') << p->Name;
fout << left << setw(12) << setfill(' ') << p->Student_ID;
fout << left << setw(8) << setfill(' ') << p->Gender;
fout << left << setw(10) << setfill(' ') << p->Age;
fout << left << setw(14) << setfill(' ') << p->Class;
fout << left << setw(18) << setfill(' ') << p->Health_Status << endl;
}
fout.close(); //关闭该文件流
}
void Read_Every_Student_TXT() //从文件中读取学生信息
{
ifstream fin("H:\\Visual Studio 2015\\My projects\\Linked_List\\Linked_List\\Student.txt");
if (!fin.is_open())
{
cout << "文件打开失败!!!";
return;
}
Node *p = Head_Point;
char status[80]; //文件中的第一行默认显示一些信息,所以这一行信息应该被读取掉然后丢弃
fin.getline(status,100); //读取100个字符到getline中
string Name;
int Student_ID;
string Gender;
int Age;
string Class;
string Health_Status;
while (fin.good()) //good()可以获取是否处于一种好的状态,达到文件尾部或者类型不匹配都会返回false
{ //将文件中的信息添加到链表中
fin >> Name >> Student_ID >> Gender >> Age >> Class >> Health_Status;
this->Add_Student(Name ,Student_ID ,Gender ,Age , Class ,Health_Status);
}
fin.close(); //关闭文件流
}
void Add_Student(string name); //添加学生,利用节点的构造函数添加一个学生
void Add_Student(string name, int student_id, string gender, int age, string Class, string health_status);
//输入所有信息直接创建
int Show_Print_Menu(); //显示打印菜单
int Show_Edit_Menu(); //显示编辑菜单
int Show_Query_Menu(); //显示查询菜单
int Show_Main_Menu(); //显示主菜单
};
#endif
⒉Linked_List.cpp
#include "stdafx.h"
#include"Linked_List.h"
bool Linked_List::Is_Previous = true; //默认取指向前一个学生的指针
void Linked_List::Clear_Linked_List()
{
Node *p, *q;
p = this->Head_Point;
for (int i = 1; i <= this->Student_Count; i++)
{ //从头节点开始销毁,每次保存销毁节点的后一个节点,以便销毁其后的节点
q = p;
p = p->Next_Student;
delete q;
}
delete p; //创建的节点数目应该是头节点数加上学生数,所以这里最后还需要销毁最后一个学生信息
this->Student_Count = 0;
}
Linked_List::Linked_List(const Linked_List &list)
{ //实现两个链表的深拷贝
Node *q = list.Head_Point;
Linked_List *p = new Linked_List; //创建一个新的链表
Node *k = new Node;
for (int i = 1; i <= list.Student_Count; i++)
{
q = q->Next_Student;
p->Add_Student(q->Name, q->Student_ID, q->Gender, q->Age, q->Class, q->Health_Status);
}
}
void Linked_List::Print_Student_Details(string name)
{
Node *p = Find_Name(name);
if (p->Name != "NULL")
{
cout << "姓名" << " 学号" << " 性别" << " 年龄" << " 班级" << " 健康状况" << endl;
cout << left << setw(15) << setfill(' ') << p->Name;
cout << left << setw(12) << setfill(' ') << p->Student_ID;
cout << left << setw(8) << setfill(' ') << p->Gender;
cout << left << setw(10) << setfill(' ') << p->Age;
cout << left << setw(14) << setfill(' ') << p->Class;
cout << left << setw(18) << setfill(' ') << p->Health_Status << endl;
}
}
void Linked_List::Print_Student_Details(int studeng_id)
{
Node *p = Find_Student_Id(studeng_id);
if (p->Name != "NULL")
{
cout << "姓名" << " 学号" << " 性别" << " 年龄" << " 班级" << " 健康状况" << endl;
cout << left << setw(15) << setfill(' ') << p->Name;
cout << left << setw(12) << setfill(' ') << p->Student_ID;
cout << left << setw(8) << setfill(' ') << p->Gender;
cout << left << setw(10) << setfill(' ') << p->Age;
cout << left << setw(14) << setfill(' ') << p->Class;
cout << left << setw(18) << setfill(' ') << p->Health_Status << endl;
}
}
void Linked_List::Print_Every_Student()
{
Node *p;
p = Head_Point;
cout << "姓名" << " 学号" << " 性别" << " 年龄" << " 班级" << " 健康状况" << endl;
for (int i = 1; i <= Student_Count; i++)
{
p = p->Next_Student;
cout << left << setw(15) << setfill(' ') << p->Name;
cout << left << setw(12) << setfill(' ') << p->Student_ID;
cout << left << setw(8) << setfill(' ') << p->Gender;
cout << left << setw(10) << setfill(' ') << p->Age;
cout << left << setw(14) << setfill(' ') << p->Class;
cout << left << setw(18) << setfill(' ') << p->Health_Status << endl;
}
}
void Linked_List::Add_Student(string name)
{
Node *p = Head_Point;
Node *q = new Node(name);
Student_Count++;
if (Student_Count == 1)
{
Head_Point->Next_Student = q;
}
else
{
for (int i = 1; i < Student_Count; i++)
{
p = p->Next_Student;
}
}
p->Next_Student = q;
return;
}
void Linked_List::Add_Student(string name, int student_id, string gender, int age, string Class, string health_status)
{
Node *p = Head_Point;
Node *q = new Node(name, student_id, gender, age, Class, health_status);
//创建一个节点并将它与链表连接
Student_Count++;
for (int i = 1; i < Student_Count; i++)
{
p = p->Next_Student;
}
p->Next_Student = q;
return;
}
int Linked_List::Show_Print_Menu()
{
for (; 1;) //进行一些操作之后便于快速跳出该菜单
{
system("cls");
cout << " ┎┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┒" << endl;
cout << " ┋ 学生教务管理系统 ┋" << endl;
cout << " ┋ ①姓名排序 ②学号排序 ┋" << endl;
cout << " ┋ ③添加顺序 ④返回菜单 ┋" << endl;
cout << " ┋ ┋" << endl;
cout << " ┖┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┚" << endl;
cout << "请输入相应操作前面的序号:";
int Operation_Number;
cin >> Operation_Number;
if (Operation_Number == 4)
{
system("cls"); //清空控制台的显示
break;
}
if (Operation_Number == 3)
{
Print_Every_Student();
system("pause"); //显示打印结果,等待我们按任意键再进入到菜单选项
}
if (Operation_Number == 2)
{
Linked_List Id_Sort;
Id_Sort = *this; //调用赋值构造函数
Id_Sort.Student_Id_Sort();
Id_Sort.Print_Every_Student();
Id_Sort.Clear_Linked_List(); //打印完成之后销毁排好序的链表
system("pause");
}
if (Operation_Number == 1)
{
Linked_List Name_Sort;
Name_Sort = *this;
Name_Sort.Student_Name_Sort();
Name_Sort.Print_Every_Student();
Name_Sort.Clear_Linked_List();
system("pause");
}
}
return 0;
}
int Linked_List::Show_Main_Menu() //子菜单的跳转
{
for (; 1;)
{
cout << " ┎┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┒" << endl;
cout << " ┋ 学生教务管理系统 ┋" << endl;
cout << " ┋ ①查询数据 ②修改数据 ┋" << endl;
cout << " ┋ ③打印数据 ④退出系统 ┋" << endl;
cout << " ┋ ┋" << endl;
cout << " ┖┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┚" << endl;
cout << "请输入相应操作前面的序号:";
int Operation_Number;
cin >> Operation_Number;
if (Operation_Number == 4)
{
exit(1); //退出程序
}
if (Operation_Number == 3)
{
Show_Print_Menu();
continue; //从上一个菜单退出之后,重新开始主菜单栏的显示
}
if (Operation_Number == 2)
{
Show_Edit_Menu();
continue;
}
if (Operation_Number == 1)
{
Show_Query_Menu();
continue;
}
}
return 0;
}
int Linked_List::Show_Query_Menu()
{
bool Is_Back = false;
for (; 1;)
{
system("cls");
cout << " ┎┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┒" << endl;
cout << " ┋ 学生教务管理系统 ┋" << endl;
cout << " ┋ ①姓名查询 ②学号查询 ┋" << endl;
cout << " ┋ ③返回菜单 ┋" << endl;
cout << " ┋ ┋" << endl;
cout << " ┖┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┚" << endl;
cout << "请输入相应操作前面的序号:";
int Operation_Number;
cin >> Operation_Number;
if (Operation_Number == 3)
{
system("cls");
break;
}
else if (Operation_Number == 2)
{
Is_Previous = false; //查询指向当前的节点
cout << "请输入学生学号:";
int student_id;
cin >> student_id;
Print_Student_Details(student_id);
system("pause");
}
else if (Operation_Number == 1)
{
Is_Previous = false; //查询指向当前的节点
cout << "请输入学生姓名:";
string name;
cin >> name;
// cout << "找到学生信息如下:" << endl;
Print_Student_Details(name);
system("pause");
}
else
{
cout << "你的输入有误,请重新输入!";
system("pause");
}
}
return 0;
}
int Linked_List::Show_Edit_Menu()
{
for (; 1;)
{
system("cls");
cout << " ┎┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┒" << endl;
cout << " ┋ 学生教务管理系统 ┋" << endl;
cout << " ┋ ①增加学生 ②删除学生 ┋" << endl;
cout << " ┋ ③编辑学生 ④返回菜单 ┋" << endl;
cout << " ┋ ┋" << endl;
cout << " ┖┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉┚" << endl;
cout << "请输入相应操作前面的序号:";
int Operation_Number;
cin >> Operation_Number;
if (Operation_Number == 4)
{
system("cls");
break;
}
if (Operation_Number == 3)
{
Is_Previous = false; //编辑学生信息需要指向当前学生
Edit_Student();
system("pause");
}
if (Operation_Number == 2)
{
Is_Previous = true; //如果要删除一个学生,需要指向他前一个学生,才能进行指针的修改
Delete_Student();
system("pause");
}
if (Operation_Number == 1)
{
Is_Previous = false;
string name;
cout << "请你输入将要添加的学生姓名:";
cin >> name;
Add_Student(name);
cout << "添加成功!添加的信息如下:" << endl;
Print_Student_Details(name);
system("pause");
}
}
return 0;
}
Node* Linked_List::Find_Name(string name)
{
int i;
Node *k = Head_Point;
Node *q, *t;
q = Head_Point;
t = Head_Point;
for (i = 0; i < Student_Count; i++)
{
t = q;
q = q->Next_Student;
if (q->Name == name)
{
if (Is_Previous)return t; //返回指向前一个学生的指针
else break; //返回指向当前学生的指针
}
}
if (i == Student_Count) //如果所有节点遍历完都还没有找到这个学生就进行以下操作
{
cout << "学生管理系统中并没有登记过该学生!" << endl;
return k; //没有找到就返回头节点,因为头节点的数据是NULL,可以对它的Name等属性进行判断知道是否找到
}
return q;
}
Node* Linked_List::Find_Student_Id(int studeng_id)
{
int i;
Node *k = Head_Point;
Node *q, *t;
q = Head_Point;
t = Head_Point;
for (i = 0; i <Student_Count; i++)
{
t = q;
q = q->Next_Student;
if (q->Student_ID == studeng_id)
{
if (Is_Previous)return t;
else break;
}
}
if (i == Student_Count)
{
cout << "学生管理系统中并没有登记过该学生!" << endl;
return k;
}
return q;
}
void Linked_List::Delete_Student()
{
char Operator_char;
string name;
cout << "请输入你想删除的学生姓名:";
cin >> name;
Node *p = Find_Name(name);
Is_Previous = false;
Print_Student_Details((p->Next_Student->Name));
//显示学生信息确定是否要删除
for (; 1;)
{
cout << "你确定要删除该学生?(Y确认N取消)" << endl;
cin >> Operator_char;
if (Operator_char == 'Y' || Operator_char == 'y')
{
Student_Count--;
if (p->Next_Student != NULL)
p->Next_Student = p->Next_Student->Next_Student;
else
{
p->Next_Student = NULL;
}
cout << "你已经成功删除该学生!";
break;
}
else if (Operator_char == 'N' || Operator_char == 'n')
{
cout << "你已经成功取消该操作!";
break;
}
else
{
cout << "你的输入有误,请重新输入!";
}
}
return;
}
void Linked_List::Edit_Student()
{
string name;
cout << "请你输入想要修改的学生姓名:";
cin >> name;
Node *now = new Node;
Node *p = Find_Name(name);
cout << "请你输入修改后的名字:";
cin >> now->Name;
cout << endl;
if (now->Name != "NULL")
{
p->Name = now->Name;
}
cout << "请你输入修改后的学号:";
cin >> now->Student_ID;
cout << endl;
if (now->Student_ID != NULL)
{
p->Student_ID = now->Student_ID;
}
cout << "请你输入修改后的性别:";
cin >> now->Gender;
cout << endl;
if (now->Gender != "NULL")
{
p->Gender = now->Gender;
}
cout << "请你输入修改后的年龄:";
cin >> now->Age;
cout << endl;
if (now->Age != NULL)
{
p->Age = now->Age;
}
cout << "请你输入修改后的班级:";
cin >> now->Class;
cout << endl;
if (now->Class != "NULL")
{
p->Class = now->Class;
}
cout << "请你输入修改后的健康状况:";
cin >> now->Health_Status;
cout << endl;
if (now->Health_Status != "NULL")
{
p->Health_Status = now->Health_Status;
}
cout << "修改后的学生情况如下:"<<endl;
Print_Student_Details(name);
delete now;
}
void Linked_List::Student_Id_Sort()
{ //冒泡排序法对学号进行排序,主要是指针间的关系改动
int j = 0;
Node *k;
Node *p;
Node *q;
for (int i = 0; i < Student_Count - 1; i++)
{
k = Head_Point;
p = Head_Point->Next_Student;
q = Head_Point->Next_Student->Next_Student;
for (j = 0; j < Student_Count - 1 - i; j++)
{
if (p->Student_ID > q->Student_ID)
{
k->Next_Student = q;
p->Next_Student = q->Next_Student;
q->Next_Student = p;
k = k->Next_Student;
q = p->Next_Student;
}
else
{
k = k->Next_Student;
p = p->Next_Student;
q = q->Next_Student;
}
}
}
}
void Linked_List::Student_Name_Sort()
{
int j = 0;
Node *k;
Node *p;
Node *q;
for (int i = 0; i < Student_Count - 1; i++)
{
k = Head_Point;
p = Head_Point->Next_Student;
q = Head_Point->Next_Student->Next_Student;
for (j = 0; j < Student_Count - 1 - i; j++)
{
int a = Get_First_Pinyin(p->Name);
int b = Get_First_Pinyin(q->Name);
if (a> b)
{
k->Next_Student = q;
p->Next_Student = q->Next_Student;
q->Next_Student = p;
k = k->Next_Student;
q = p->Next_Student;
}
else
{
k = k->Next_Student;
p = p->Next_Student;
q = q->Next_Student;
}
}
}
}
Linked_List& Linked_List::operator=(const Linked_List &list)
{ //类似于拷贝构造函数
Linked_List *p = new Linked_List;
Head_Point = p->Head_Point;
Node *k = list.Head_Point;
for (int i = 1; i <= list.Student_Count; i++)
{
k = k->Next_Student;
p->Add_Student(k->Name, k->Student_ID, k->Gender, k->Age, k->Class, k->Health_Status);
}
Student_Count = p->Student_Count;
return *this;
}
⒊main.cpp
这里面都是一些测试代码:
#include "stdafx.h"
#include"Linked_List.h"
#include<iostream>
#include<string>
#include <locale.h>
using namespace std;
int main()
{
Linked_List List;
List.Add_Student("王小林", 790635, "男", 18, "计算机91班", "健康");
List.Add_Student("陈红", 790636, "女", 20, "计算机91班", "一般");
List.Add_Student("刘建平", 790637, "男", 21, "计算机91班", "健康");
List.Add_Student("张立立", 790638, "男", 17, "计算机91班", "神经衰弱");
List.Add_Student("邓小林", 790631, "男", 18, "计算机91班", "健康");
List.Add_Student("谢红", 790632, "女", 20, "计算机91班", "一般");
List.Add_Student("李平", 790633, "男", 21, "计算机91班", "健康");
List.Add_Student("宋立", 790634, "男", 17, "计算机91班", "神经衰弱");
List.Write_Every_Student_TXT();
// List.Read_Every_Student_TXT();
List.Show_Main_Menu();
return 0;
}
wstring String_To_WString(const string &s) //将string转化为wstring
{
setlocale(LC_ALL, "chs");
const char* _Source = s.c_str();
size_t _Dsize = s.size() + 1;
wchar_t *_Dest = new wchar_t[_Dsize];
wmemset(_Dest, 0, _Dsize);
mbstowcs(_Dest, _Source, _Dsize);
wstring result = _Dest;
delete[]_Dest;
setlocale(LC_ALL, "C");
return result;
}
const char firstLetterArray[HANZI_COUNT + 1] =
"ydkqsxnwzssxjbymgcczqpssqbycdscdqldylybssjgyqzjjfgcclzznwdwzjljpfyynnjjtmynzwzhflzppqhgccyynmjqyxxgd"
"nnsnsjnjnsnnmlnrxyfsngnnnnqzggllyjlnyzssecykyyhqwjssggyxyqyjtwktjhychmnxjtlhjyqbyxdldwrrjnwysrldzjpc"; //这里我只是截取了该字符数组的一小部分在这里,获取完整的字符数组,请自行百度pinyin.c
//这里应该存放firstLetterArray这一个数组,因为要在Get_First_Pinyin这个函数里面使用,所以应该在这个函数之前声明,又因为数组的批量赋值只有在声明的时候可以完成,所以整个字符数组都被放在这儿了。
int Get_First_Pinyin(string name)
{
wstring Name = String_To_WString(name);
char First = firstLetterArray[(Name[0] - HANZI_START)]; //将Name中第一个汉字提取出来,减去汉字在unicode码中的开始位置就是它的拼音的首字母
int a = First;
return a;
}
单链表作为一种数据结构,而学生管理系统只是它的一种应用。当我完成这个管理系统之后,领悟最多的还是关于C++的类的实现,指针的使用,很多东西,自己去做了一遍才知道问题在哪里。不动手是不会知道自己是否可以实现一些事情的,努力去做才会有好事发生。