一、程序实验要求
二、框架构建
首先这个程序包含的文件一共有如下5个:input.txt,menu.txt,find.txt,insert.txt,out.txtx。其中input.cpp又可以分成三个部分(函数重载),input就是读取文件输入数据所用。我们使用如下几个函数实现功能:
- volunteer* input(const char* fileName);//读取input文件并创建链表
- void input(const char* fileName, volunteer* q);//读取insert文件
- void input(const char* fileName, int& num);//读取menu文件或find文件
然后是output.cpp,它对应数据输出到 文件中。
void output(volunteer* head, const char* fileName);//将链表内容写入文件
find.cpp:
volunteer* find(volunteer* head, int no);//查找number为no的人员,并返回该结点前一结点便于删除函数调用
del.cpp :
volunteer* del(volunteer* head, int no);//从链表中删除number为no的人员,返回链首
append.cpp:
volunteer* append(volunteer* head, volunteer* s);//插入一名人员至链尾,返回链首
大体框架已经搭建好,我们给出头文件project.h
#pragma once
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
struct volunteer
{
int number;
char name[20];
int age;
char gender;
char language[10];
double grade;
volunteer* next;
};
volunteer* input(const char* fileName);//读取input文件并创建链表
void input(const char* fileName, volunteer* q);//读取insert文件
void input(const char* fileName, int& num);//读取menu文件或find文件
void output(volunteer* head, const char* fileName);//将链表内容写入文件
volunteer* find(volunteer* head, int no);//查找number为no的人员,并返回该结点前一结点便于删除函数调用
volunteer* del(volunteer* head, int no);//从链表中删除number为no的人员,返回链首
volunteer* append(volunteer* head, volunteer* s);//插入一名人员至链尾,返回链首
接下来的内容就是对每个部分实现函数的填充。
三、写入函数
-
input.cpp
volunteer* input(const char* fileName)//读取input文件并创建链表
// 从给定的文件名中读取志愿者信息,并返回链表的头指针
volunteer* input(const char* fileName)
{
ifstream inputFile; // 定义一个输入文件流对象
inputFile.open(fileName, ios::in); // 使用输入模式打开指定的文件
volunteer* head = new volunteer; // 创建一个新的志愿者节点作为链表的头结点
volunteer* per = new volunteer; // 创建一个临时指针,用于遍历链表
head->next = per; // 将头结点的下一个节点指向per,为后续的链表连接做准备
per = head; // 移动临时指针到头结点
do {
volunteer* q = new volunteer; // 为新的志愿者创建一个节点
inputFile >> q->number >> q->name >> q->age >> q->gender >> q->language >> q->grade; // 从文件中读取志愿者的信息
q->next = NULL; // 设置新创建的节点的下一个节点为NULL,表示当前节点是链表的结尾
per->next = q; // 将当前节点的下一个节点指向新创建的节点,将新节点添加到链表的末尾
per = q; // 移动临时指针到新的节点,为读取下一个志愿者的信息做准备
} while (!inputFile.eof()); // 循环直到文件末尾
per->next = NULL; // 设置链表的最后一个节点的下一个节点为NULL,表示链表的结尾
return head; // 返回链表的头指针
}
void input(const char* fileName, volunteer* p) // 函数定义
{
ifstream inputFile(fileName); // 尝试打开指定文件名的文件
if (!inputFile.is_open()) // 检查文件是否成功打开
{
cout << "文件无法打开" << endl; // 如果文件无法打开,输出错误信息
return; // 结束函数执行
}
inputFile >> p->number >> p->name >> p->age >> p->gender >> p->language >> p->grade; // 从文件中读取志愿者信息,并存储在p指向的结构体中
}
void input(const char* fileName, int& num) // 函数定义
{
ifstream inputFile(fileName); // 尝试打开指定文件名的文件
if (!inputFile.is_open()) // 检查文件是否成功打开
{
cout << "文件无法打开" << endl; // 如果文件无法打开,输出错误信息
return; // 结束函数执行
}
inputFile >> num; // 从文件中读取一个整数并存储在num中
}
首先就是读取文件,这里我们使用ifstream。然后这里跟上对文件是否打开的检测:
ifstream inputFile(fileName);
if (!inputFile.is_open())
{
cout << "文件无法打开" << endl;
return NULL;
}
然后我们创建一个链表,创建它的head节点和一个p节点,以及一个tail节点(用来给p->next分配内存)
- output.cpp
void output(volunteer* head, const char* fileName)//将链表内容写入文件
void output(volunteer* head, const char* fileName)//将链表内容写入文件
{
ofstream outputFile(fileName);
if (!outputFile.is_open())
{
cout << "文件打开失败" << endl;
return;
}
volunteer* p = head->next;
while (p != NULL)
{
outputFile << p->number << p->name << p->age << p->gender << p->language << p->grade << endl;
p = p->next;
}
outputFile.close();
}
这个程序中所需要和文件建立关系的就input.cpp和output.cpp,这里我们先和out.txt建立联系。然后和普通的链表操作一样,先创建一个p指针,实现输出。最后记得 outputFile.close();就行。
-
find.cpp
volunteer* find(volunteer* head, int no)//查找number为no的人员,并将该节点接到头节点之后方便output.cpp调用
这里为什么说是方便output.cpp调用呢?因为我们删除功能仅仅是读取find.txt而不是用find.cpp。find.cpp仅仅是为了方便查找功能的输出。
volunteer* find(volunteer* head, int no)//查找number为no的人员,并将该节点接到头节点之后方便output.cpp调用
{
volunteer* p = head->next;
while (p != NULL)
{
if (p->number == no)
{
head->next = p;
p->next = NULL;
return head;
}
p = p->next;
}
return head;
}
-
append.cpp
volunteer* append(volunteer* head, volunteer* s)//插入一名人员至链尾,返回链首
volunteer* append(volunteer* head, volunteer* s)//插入一名人员至链尾,返回链首
{
volunteer* p = head;
while (p->next != NULL)
{
p = p->next;
}//p到链表尾部
volunteer* tmp = new volunteer;
if (tmp == NULL)
{
return 0;
}//内存不够,返回
tmp = s;
tmp->next = NULL;
p->next = tmp;
return head;
}
这里是链表尾插法的实现。
-
del.cpp
volunteer* del(volunteer* head, int no)//从链表中删除number为no的人员,返回链首
volunteer* del(volunteer* head, int no)//从链表中删除number为no的人员,返回链首
{
volunteer* tmp = NULL;
volunteer* p = head;
while (p->next != NULL)
{
if (p->next->number == no)
{
tmp = p->next;
p->next = p->next->next;
delete tmp;
return head;
}
p = p->next;
}
}
-
FileName.cpp
#include"project.h"
using namespace std;
int main()
{
volunteer* head = NULL;
head = input("input.txt");//读入input.txt
int num = 0;
input("menu.txt", num);//读入menu.txt
switch (num)
{
case 1:
{
int number = 0;
input("find.txt", number);//读入find.txt
head=find(head, number);
output(head, "out.txt");
break;
}
case 2:
{
volunteer* person = new volunteer;
input("insert.txt", person);
head = append(head, person);
output(head, "out.txt");
break;
}
case 3:
{
int number = 0;
input("find.txt", number);
head = del(head, number);
output(head, "out.txt");
break;
}
}
return 0;
}
四、总结
遇到过的问题:
- 最开始没有把q->next马上置为空
- input.txt文件在文件末尾多出了一个换行符