用单链表实现学生健康情况管理的几个操作功能(新建、插入、删除、从文件读取、写入文件和查询、屏幕输出等功能)。健康表中学生的信息有学号、姓名、出生日期、性别、身体状况等。
目录
关键词
链式结构 类模板 结构体 文件输入输出
1)建立结点类模板
//声明单链表类模板
template <class Type> class List;
//定义链表结点类模板
template <class Type>
class ListNode {
private:
friend class List<Type>;//单链表类是链表结点类的友元类
Type data; //结点数据域
ListNode<Type> * next; //结点指针域
public:
ListNode() :next(NULL) { }
ListNode(Type& item) :data(item), next(NULL) {}
//建立一个新结点
ListNode<Type>* CreateNode(Type& item, ListNode<Type>* next = NULL);
//取得结点中数据
Type GetData() { return data; }
//取得结点中指针值
ListNode<Type>* GetPointer() { return next; }
//设置结点的data值
void SetDate(Type value) { data = value; }
//修改结点的指针值
void SetPointer(ListNode<Type>* nextT) { next = nextT; }
};
其中建立新结点时要与后一个结点连接
//建立一个新结点
template <class Type>
ListNode<Type>* ListNode<Type>::CreateNode(Type& item, ListNode<Type>* next ) {
ListNode<Type>* newNode = new ListNode<Type>(item);
// 将当前结点后面的结点接在新建结点上
newNode->next = next;
return newNode;
}
2)建立链表类模板
写入结点类模板为友元函数
//定义单链表类模板
template <class Type> class List {
private:
//链表的表头指针和当前结点指针
ListNode<Type>* first, * current;
public:
//构造带头结点的单链表(空表)
List(){ //头结点无数据
first = current = new ListNode<Type>;
}
~List(){
MakeEmpty();//置空表
delete first, current;
}
void MakeEmpty();//将链表置空
int Length() const; //计算链表的长度
ListNode<Type>* Firster() { return first; }//返回头结点地址
ListNode<Type>* Find(Type value); //搜索含数据value的结点并置为当前结点
Type GetData(); //获得当前结点的数据
void Insert(Type value); //插入数据
void RemoveCurrentNode(Type value); //将链表当前结点删去
Type* Next();//获得当前结点后继的数据域地址
bool IsEmpty(){//判断表空
return Length() == 0 ? true : false;
}
void Dispaly();//输出链表
};
3)定义一系列链表操作
链表置空
//链表置空
template <class Type>
void List<Type>::MakeEmpty(){
//删去链表中除表头结点外的所有其他结点
ListNode<Type>* q;
while (first->next != NULL) {
q = first->next;
first->next = q->next;
delete q;
}
current = first;
}
计算链表长度
//获取表长
template <class Type>
int List<Type>::Length() const{
ListNode<Type>* p = first->next;
int count = 0;
while (p != NULL) {
count++;
p = p->next;
}
return count;
}
插入结点
//插入数据 尾插法
template<class Type>
void List<Type>::Insert(Type value) {
if (current == NULL) {
cout << "插入失败!" << endl;
return;
}
ListNode<Type>* newNode = current->CreateNode(value, current->next);
current = current->next = newNode;
cout << "插入成功!" << endl;
return;
}
搜索结点
//搜索含数据value的结点并返回该结点
template <class Type>
ListNode<Type>* List<Type>::Find(Type value){
ListNode<Type>* p = first->next;
while (p) {
if (p->data == value) break;
else p = p->next;
}
return p;
}
删除结点:用到搜索结点的函数
//将链表当前结点删去
template <class Type>
void List<Type>::RemoveCurrentNode(Type value){
if (current == first) {
cout << "表空,无可删除数据" << endl;
return;
}
ListNode<Type>* p = Find(value);
ListNode<Type>* prior = first;
//寻找当前元素的前驱元素结点
while (prior->next != p)
prior = prior->next;
prior->next = p->next;
delete p;
cout << "删除成功!" << endl;
return;
}
输出链表所有值。
//显示输出链表
template <class Type>
void List<Type>::Dispaly() {
ListNode<Type>* p = current;
current = first->next;
while (current) {
cout << current->data << " ";
current = current->next;
}
cout << endl;
current = p;
}
4)定义学生结构体类型
转换为类模板中的类型,结构体的输入输出等运算符进行重载,便于数据的读写操作
//学生结构体
typedef struct student {
int num;
char name[10];
string birth;
string sex;
string body;
//重载运算符
friend istream& operator >> (istream& is, student& t) {
is >> t.num >> t.name >> t.birth >> t.sex >> t.body;
return is;
}
friend ostream& operator << (ostream& os, student& t) {
os << t.num << '\t' << t.name << '\t' << t.birth << '\t' << t.sex << '\t' << t.body << endl;
return os;
}
bool operator ==(const student& t) {
return this->num == t.num;
}
bool operator !=(const student& t) {
return this->num != t.num;
}
}stutype;
5)各功能函数
这里只放文件读写操作函数
//从文件中读取信息
void readfile() {
ifstream ifs("student.txt"); //读取文件
if (!ifs.good()) {
cerr << "ifstream open file error!\n";
return;
}
string line;
vector<string> lines;
while (getline(ifs, line)) {
lines.push_back(line); //将每一行依次存入到vector中
cout << line << endl; //顺便打印一下这一行
}
ifs.close();
return;
}
文件写入时遇到一个问题:运行时会报错为显示p为空指针,加上判断p为空则返回即可,解决方法参考的是这个哥的http://t.csdnimg.cn/sl8vp 感恩
void infile() {
fstream fout("student.txt", ios::out | ios::app);
if (fout.fail()) {
cout << "文件打开失败" << endl;
exit(0);
}
ListNode<stutype> * p = stu.Firster();
p = p->GetPointer();
while (p) {
fout << p->GetData().num << '\t' << p->GetData().name << '\t' << p->GetData().birth
<< '\t' << p->GetData().sex << '\t' << p->GetData().body << endl;
p = p->GetPointer();
if (p == NULL) break;
}
fout.close();
cout << "写入成功!" << endl;
return;
}
完整代码实现
#include <iostream>
using namespace std;
#include<string>
#include<fstream>
#include<vector>
//声明单链表类模板
template <class Type> class List;
//定义链表结点类模板
template <class Type>
class ListNode {
private:
friend class List<Type>;//单链表类是链表结点类的友元类
Type data; //结点数据域
ListNode<Type> * next; //结点指针域
public:
ListNode() :next(NULL) { }
ListNode(Type& item) :data(item), next(NULL) {}
//建立一个新结点
ListNode<Type>* CreateNode(Type& item, ListNode<Type>* next = NULL);
//取得结点中数据
Type GetData() { return data; }
//取得结点中指针值
ListNode<Type>* GetPointer() { return next; }
//设置结点的data值
void SetDate(Type value) { data = value; }
//修改结点的指针值
void SetPointer(ListNode<Type>* nextT) { next = nextT; }
};
//建立一个新结点
template <class Type>
ListNode<Type>* ListNode<Type>::CreateNode(Type& item, ListNode<Type>* next ) {
ListNode<Type>* newNode = new ListNode<Type>(item);
// 将当前结点后面的结点接在新建结点上
newNode->next = next;
return newNode;
}
//定义单链表类模板
template <class Type> class List {
private:
//链表的表头指针和当前结点指针
ListNode<Type>* first, * current;
public:
//构造带头结点的单链表(空表)
List(){ //头结点无数据
first = current = new ListNode<Type>;
}
~List(){
MakeEmpty();//置空表
delete first, current;
}
void MakeEmpty();//将链表置空
int Length() const; //计算链表的长度
ListNode<Type>* Firster() { return first; }//返回头结点地址
ListNode<Type>* Find(Type value); //搜索含数据value的结点并置为当前结点
Type GetData(); //获得当前结点的数据
void Insert(Type value); //插入数据
void RemoveCurrentNode(Type value); //将链表当前结点删去
Type* Next();//获得当前结点后继的数据域地址
bool IsEmpty(){//判断表空
return Length() == 0 ? true : false;
}
void Dispaly();//输出链表
};
//链表置空
template <class Type>
void List<Type>::MakeEmpty(){
//删去链表中除表头结点外的所有其他结点
ListNode<Type>* q;
while (first->next != NULL) {
q = first->next;
first->next = q->next;
delete q;
}
current = first;
}
//获取表长
template <class Type>
int List<Type>::Length() const{
ListNode<Type>* p = first->next;
int count = 0;
while (p != NULL) {
count++;
p = p->next;
}
return count;
}
//插入数据 尾插法
template<class Type>
void List<Type>::Insert(Type value) {
if (current == NULL) {
cout << "插入失败!" << endl;
return;
}
ListNode<Type>* newNode = current->CreateNode(value, current->next);
current = current->next = newNode;
cout << "插入成功!" << endl;
return;
}
//获得当前结点的数据域的地址
template <class Type>
Type List<Type>::GetData(){
if (current == NULL)
return NULL;
else
return current->GetData();
}
//搜索含数据value的结点并返回该结点
template <class Type>
ListNode<Type>* List<Type>::Find(Type value){
ListNode<Type>* p = first->next;
while (p) {
if (p->data == value) break;
else p = p->next;
}
return p;
}
//将链表当前结点删去
template <class Type>
void List<Type>::RemoveCurrentNode(Type value){
if (current == first) {
cout << "表空,无可删除数据" << endl;
return;
}
ListNode<Type>* p = Find(value);
ListNode<Type>* prior = first;
//寻找当前元素的前驱元素结点
while (prior->next != p)
prior = prior->next;
prior->next = p->next;
delete p;
cout << "删除成功!" << endl;
return;
}
//获得当前结点后继的数据域地址
template <class Type>
Type* List<Type>::Next(){
if (current == NULL || current->next == NULL)
return NULL;
current = current->next;
return current->GetData();
}
//显示输出链表
template <class Type>
void List<Type>::Dispaly() {
ListNode<Type>* p = current;
current = first->next;
while (current) {
cout << current->data << " ";
current = current->next;
}
cout << endl;
current = p;
}
//学生结构体
typedef struct student {
int num;
char name[10];
string birth;
string sex;
string body;
//重载运算符
friend istream& operator >> (istream& is, student& t) {
is >> t.num >> t.name >> t.birth >> t.sex >> t.body;
return is;
}
friend ostream& operator << (ostream& os, student& t) {
os << t.num << '\t' << t.name << '\t' << t.birth << '\t' << t.sex << '\t' << t.body << endl;
return os;
}
bool operator ==(const student& t) {
return this->num == t.num;
}
bool operator !=(const student& t) {
return this->num != t.num;
}
}stutype;
List<stutype> stu;//新建
void meau() {
cout << "1------新建学生健康表" << endl
<< "2------向学生健康表插入学生信息" << endl
<< "3------在健康表删除学生信息" << endl
<< "4------从文件中读取健康表信息" << endl
<< "5------向文件写入学生健康表信息" << endl
<< "6------在健康表中查询学生信息(按学生学号来进行查找)" << endl
<< "7------在屏幕中输出全部学生信息" << endl
<< "8------退出" << endl
<< "请输入需要使用的功能:";
return;
}
//从文件中读取信息
void readfile() {
ifstream ifs("student.txt"); //读取文件
if (!ifs.good()) {
cerr << "ifstream open file error!\n";
return;
}
string line;
vector<string> lines;
while (getline(ifs, line)) {
lines.push_back(line); //将每一行依次存入到vector中
cout << line << endl; //顺便打印一下这一行
}
ifs.close();
return;
}
//向文件写入信息
void infile() {
fstream fout("student.txt", ios::out | ios::app);
if (fout.fail()) {
cout << "文件打开失败" << endl;
exit(0);
}
ListNode<stutype> * p = stu.Firster();
p = p->GetPointer();
while (p) {
fout << p->GetData().num << '\t' << p->GetData().name << '\t' << p->GetData().birth
<< '\t' << p->GetData().sex << '\t' << p->GetData().body << endl;
p = p->GetPointer();
if (p == NULL) break;
}
fout.close();
cout << "写入成功!" << endl;
return;
}
//插入学生信息
void instu() {
student data;
cout << "请依次输入要插入的学生学号、姓名、出生日期、性别、身体状况:(使用空格间隔)" << endl;
cin >> data;
stu.Insert(data);
return;
}
//删除学生信息
void delstu() {
student data;
cout << "请输入要删除的学生学号:";
cin >> data.num;
stu.RemoveCurrentNode(data);
return;
}
//查询学生信息
void findstu() {
student data;
cout << "请输入要查询的学生学号:";
cin >> data.num;
if (stu.Find(data) == NULL) cout << "查无此人" << endl;
else {
student o = stu.Find(data)->GetData();
cout << o;
}
return;
}
//输出所有学生信息
void showstu() {
stu.Dispaly();
return;
}
int main() {
int a;
while (true) {
meau();
cin >> a;
switch (a) {
case 1:
cout << "学生表已建立,请返回菜单进行插入数据操作!" << endl;
break;
case 2:
//插入学生信息
instu();
break;
case 3:
//删除学生信息
delstu();
break;
case 4:
//文件中读取信息
readfile();
break;
case 5:
//文件中写入信息
infile();
break;
case 6:
//查询学生信息 学号查询
findstu();
break;
case 7:
//输出所有学生信息
showstu();
break;
case 8:
//推出
return 0;
default:
cout << "请重新输入:";
}
system("pause");
system("cls");
}
}