课程设计报告书
之前写的,忘发布了...
在C++学习了一段时间之后,我们开始入了课程设计。我选择的题目是:《新生基本信息统计软件》。
题目要求:
有新生来报到,要逐个录入其信息,如:学生姓名,性别,专业,出生日期,家庭地址,英语入学成绩。要求设计链表类来实现,并统计学生人数。文本界面为:
- 新增学生信息
- 删除学生信息
- 导入学生信息(已经保存于的文件信息)
- 学生信息搜索(按姓名)
- 学生信息统计(按专业或性别或年龄---年龄要自动计算)
- 按英语成绩排序
- 学生信息保存
- 退出
初学了一些简单的语法之后,感觉要完成一项工程还是有些困难的。
我觉得课程设计的核心,是对链表的操作,实现动态链表的增、删、改、查。还要体现面对对象的思想,相比于C语言的结构体,引入了类的概念。 在写课程设计时,比起一下子打出来完,不如分模块,分功能的有步骤的去写。
类的创建
创建了两个类,一个是student类,用于储存学生信息,另一个studentmanage类,用于实现各类功能。
Studentmanage里的函数,实质上就是指向student的类指针,比如说:Student *Studentmanage::creat() 。
这是一个可控长度的链表,靠的就是不断的新申请空间,直到某终止条件出现,比如我的就是当学生姓名为#时,跳出当前循环,停止录入。
在第一个节点需要特殊处理,即对头结点初始化,之后就是申请空间,初始化,挪指针的循环往复了。重点是最后一个结点的后继要赋空(NULL)。
- 增
此功能是建立在已形成的链表上的,所以如果链表为空,就跳出。
不为空时,申请一片空间,并初始化。这并不是就插在原链表的最后,而是找了头结点的后一个,把新添加的放到了二者中间。
删
和增一样,删要求原本就存在链表。
按照姓名删除,对比要删除的姓名,如果出现。
有两种情况,一种是头结点:直接让头指针移向下一位,再把原结点free掉。
另一种情况:其他结点,令p1指针先向后移动一位,若不是要删除的,就每次向后位移。直到出现要删除结点,
把该指针的上一个next搭到它的下一个,把它隔过去,再free掉。改,查
这两个的原理差不多,就放到一起说 。都是通过遍历,找到需要的结点,只不过一个找到后重新录入,覆盖原本数据;另一个只是显示。
为了方便和代码的简洁,在这里我写了displaynode()函数,每次在显示和整改时会方便很多。存文件,读文件
这可以说是一个难点了,先说写入文件,即 :
当前黑框---->txt文件
这里就用到了ofstream,文件输出流类,open一个txt,要是没有就新建一个,要是原本有就覆盖。
把头赋给p1后,只要p1存值,就把它写入到out所新建的那个文件里,再让p1移动下一个。
读文件的过程就是一个新建链表的过程,先把头置空,这里有和student类里一样的数据,成功打开文件之后,把里面的数据一个个读出来,并赋值给p1。此处和创建链表也一样,不赘述。
- 排序
思想:如果说,原本的链表是无序的,而我最终的目的是创造出有序的。而且我有能力去找到这里面最大的或最小的(遍历就可以了),那么我何不再去创建一个新的链表,它是由原本链表摘出来的节点所组成,那必然是有序的。
和其他操作的最开始一样,传入了头和它之后的一串链表,于以往不同的是,这次开始了直接对头指针的操作。
(366和367是为了防止传进来一个空头造成错误。
核心代码就是white里的循环了:
第一层循环
目的是为了让头不断向后遍历,只不过这次的目的,就是遍历到终点。期间每执行一次,就让我定义的指针重新指向同一块。
第二层循环
p(也就是头)的遍历,如果后一个大于前一个,就让后一个成为max,同时定位它的前一个节点,以这种方式标记过后,p再继续向后推进,以实现在循环过后,可以过滤出来最大的,找到了又怎样呢,我们来看接下来的操作。
第一个if(379)
这时还要考虑到那种情况,也就是头结点万一最大该怎么操作,这也并不难想,直接让head指向下一位,同时断开max(也就是头)与原链表的联系。
其它情况就是,既然上一步(371 while)找出来了max,那么就在这里把它摘出来,令刚刚标记的前一项(pre)指向max的后继,在断开max与原表的联系。
第二个if(387)
细心的你会发现,在每次的赋值里和之前的几步操作里,都没有用到pnew,不仅如此,它还在一开始就被置空了。
我的目的就是让它成为那个新的链表的头。在之前几步,我们分别找到了max,分离出了max,终于要在这一步为max找一个着落了。
当然,if第一次肯定是会执行的(因为上来就让pnew置空了),我们让最大的那个节点成了新链表的第一个,那么可想而知的是,在之后几次的循环里,每次都会执行else,并且在里面新摘出来的max被一个个的连到了链表的后面。
到最后,别忘了还有那个大循环的,它每次执行一遍里面的内容。如是,原本的无序链表每次少一个节点(最大的节点),而新有序链表每次会多一个。
原链表终结之日,也就是新链表生成之时。届时,循环也就彻底结束了,于是我们令头指针指向那个新生链表(394),再让它们共同指向这条有序的链表,传回去就行了。
- 主函数的选择功能
在这里包含两块,先是一个菜单界面menu,它的返回值是一个字符型,由最后的cin写入。下面就紧接着是main函数的switch的选择功能,之所以用char而不用int就是为了规避用户乱输造成的错误。
以下,附上源代码:
#include<iostream>
#include<fstream> //用来读文件
#include<iomanip> //排版
#include<cstring>//操作字符 ,比较和赋值。
#include<stdlib.h> //new,free
using namespace std;
int n=0;
/*
1.明明head置空,为什么add,display没有出现预期效果? ok
(为什么它又莫名其妙的好了??)
2.free关键字为什么不存在? ok
3.全部删除之后无法新建
4.排序链断 ok
5.多读一次 ok
*/
char stop[12]={"#"};
char name[12];
class Student {
public:
char name[12];
char sex[3];
char study[12];
char addr[12];
int birth[3];
int engli;
Student *next;
};
class Studentmanage {
private:
Student *head,*p1,*p2,*p3;
public:
Studentmanage () {};
Student *creat();
Student *add(Student *head);
Student *delet(Student *head);
void *search(Student *head);
Student *modify(Student *head);
Student *sort(Student*head);
void display(Student *head);
void displaynode(Student *head);
void write_file(Student *head);
Student * read_file();
~Studentmanage () {};
};
Studentmanage s;
Student *Studentmanage::creat() {
p1=p2=new Student;
head=NULL;
cout<<"请输入学生的基本信息:以姓名为#结束。\n";
while(1) {
cout<<"姓名: \t";
cin>>p1->name;
if( strcmp(stop,p1->name)==0 ) {
break;
}
cout<<"性别: \t";
cin>>p1->sex;
cout<<"专业: \t";
cin>>p1->study;
cout<<"家庭住址: \t";
cin>>p1->addr;
cout<<"出生年:";
cin>>p1->birth[0];
cout<<"出生月:";
cin>> p1->birth[1];
cout<<"出生日:";
cin>>p1->birth[2];
cout<<"英语:";
cin>>p1->engli;
system("cls");
n=n+1;
if(n==1)
head=p1;
else
p2->next=p1;
p2=p1;
p1=new Student;
}
p2->next=NULL;
return head;
}
Student *Studentmanage::add(Student *head) {
p1=p3=new Student;
p1=head;
if(p1==NULL)
{cout<<"在添加前,先新建!";
return 0;
}
else
{
cout<<"请输入要添加学生的信息!\n";
cout<<"姓名: \t";
cin>>p3->name;
cout<<"性别: \t";
cin>>p3->sex;
cout<<"专业: \t";
cin>>p3->study;
cout<<"家庭住址: \t";
cin>>p3->addr;
cout<<"出生年:";
cin>>p3->birth[0];
cout<<"出生月:";
cin>> p3->birth[1];
cout<<"出生日:";
cin>>p3->birth[2];
cout<<"英语:";
cin>>p3->engli;
cout<<"\n";
p3->next=p1->next;
p1->next=p3;
cout<<"添加成功!\n";
}
return head;
}
Student *Studentmanage::delet(Student *head) {
p2=p1=new Student;
if(head==NULL)
{
cout<<"没有数据,无法删除";
return 0;
}
cout<<"请输入要删除学生的名字:\n";
cin>>name;
p2=p1=head;
int j=0;
if( ( strcmp(name,head->name)==0 ) && (head!=NULL))
{
head=head->next;
free(p1);
j=1;
}
else
{
p1=head->next;
while(p1!=NULL) {
if(strcmp(name,p1->name)==0) {
p2->next=p1->next;
free(p1);
j=1;
break;
} else {
p2=p1;
p1=p2->next;
}
}
}
if(j==0)
cout<<"此学生不存在,删除失败!\n";
else
cout<<"删除成功!\n";
return head;
}
void *Studentmanage::search(Student *head) {
p1=new Student;
cout<<"请输入要查找学生的姓名:\n";
cin>>name;
p1=head;
int j=0;
while(p1!=NULL) {
if( strcmp(name,p1->name)==0 ) {
s.displaynode(p1);
break;
}
p1=p1->next;
}
if(j==0)
cout<<"没有找到你要查找学生的信息。\n\n\n";
else
cout<<"这是你要查找学生的信息。\n\n\n";
}
Student *Studentmanage::modify(Student *head) {
if(head==NULL)
{
cout<<"没有数据,先新建吧";
return 0;
}
char name1[12];
char sex[3];
char study[12];
char addr[12];
int birth[3];
int engli;
p1=new Student;
int j=0;
p1=head;
cout<<"请输入你要更改学生的学号:\n";
cin>>name;
if(strcmp( name, head->name)==0) {
cout<<"显示要修改学生的信息:\n";
s.displaynode(p1);
cout<<"请输入要更改学生的信息:\n";
cout<<"姓名: \t";
cin>>name1;
cout<<"性别: \t";
cin>>sex;
cout<<"专业: \t";
cin>>study;
cout<<"家庭住址: \t";
cin>>addr;
cout<<"出生年:";
cin>>birth[0];
cout<<"出生月:";
cin>>birth[1];
cout<<"出生日:";
cin>>birth[2];
cout<<"英语:";
cin>>engli;
strcpy(head->name,name1);
strcpy(head->sex,sex);
strcpy(head->study,study);
strcpy(head->addr,addr);
head->birth[0]=birth[0];
head->birth[1]=birth[1];
head->birth[2]=birth[2];
head->engli=engli;
j=1;
} else {
p1=head->next;
while(p1!=NULL) {
if(strcmp(p1->name,name)==0)
cout<<"显示要修改学生的信息:\n";
s.displaynode(p1);
cout<<"请输入要更改学生的信息:\n";
cout<<"姓名: \t";
cin>>name1;
cout<<"性别: \t";
cin>>sex;
cout<<"专业: \t";
cin>>study;
cout<<"家庭住址: \t";
cin>>addr;
cout<<"出生年:";
cin>>birth[0];
cout<<"出生月:";
cin>>birth[1];
cout<<"出生日:";
cin>>birth[2];
cout<<"英语:";
cin>>engli;
strcpy(p1->name,name1);
strcpy(p1->sex,sex);
strcpy(p1->study,study);
strcpy(p1->addr,addr);
p1->birth[0]=birth[0];
p1->birth[1]=birth[1];
p1->birth[2]=birth[2];
p1->engli=engli;
j=1;
break;
}
}
if(j==0)
cout<<"没有找到你要更改的学生,更改失败!\n";
else
cout<<"更改成功!\n";
return head;
}
void Studentmanage::display(Student *head) {
p1=head;
if(p1==NULL)
cout<<"这是一个空表!请先输入学生信息。"<<endl;
else {
while(p1!=NULL) {
s.displaynode(p1);
p1=p1->next;
}
}
}
void Studentmanage::displaynode(Student *head) {
p1=head;
if(p1==NULL)
cout<<"这是一个空表!请先输入学生信息。"<<endl;
else
{
cout<<"姓名:"<<p1->name<<" 性别:"<<p1->sex<<" 专业:"<<p1->study;
cout<<" 家庭住址:"<<p1->addr<<endl;
cout<<p1->birth[0]<<"年";
cout<<p1->birth[1]<<"月:"<<p1->birth[2]<<"日 出生:";
cout<<"年龄:"<<2017-p1->birth[0]<<endl;
cout<<"英语成绩:"<<p1->engli<<"\n\n";
}
}
Student *Studentmanage::read_file()
{
int i=0;
char name2[12];
char study[12];
char sex[3];
char addr[12];
int birth[3];
int engli;
p1=p2=new Student;
head=NULL;
ifstream in;
in.open("myC++work.txt");
if(!in) {
cout<<"打开文件失败!"<<endl;
}
else
{
while(in>>name2>>sex>>study>>addr>>birth[0]>>birth[1]>>birth[2]>>engli)
{
strcpy(p1->name,name2);
strcpy(p1->sex,sex);
strcpy(p1->study,study);
strcpy(p1->addr,addr);
p1->birth[0]=birth[0];
p1->birth[1]=birth[1];
p1->birth[2]=birth[2];
p1->engli=engli;
i++;
if(i==1) {
head=p2=p1;
} else {
p2->next=p1;
}
p2=p1;
p1=new Student;
p1->next=NULL;
}
cout<<"成功读取文件!内容如下:"<<endl;
}
return head;
}
void Studentmanage::write_file(Student *head)
{
ofstream out;
out.open("myC++work.txt");
if(!out)
{
cout<<"打开文件失败!"<<endl;
}
p1=NULL;
p1=head;
while(p1) {
out<<p1->name<<setw(5)<<p1->sex<<setw(5)<<p1->study<<setw(5)<<p1->addr<<setw(5)<<p1->birth[0]<<setw(5)<<p1->birth[1]<<setw(5)<<p1->birth[2]<<setw(5)<<p1->engli<<endl;
p1=p1->next;
}
out.close();
cout<<"写入完毕。";
}
Student *Studentmanage::sort(Student *head)
{
Student*p,*pnew=NULL,*pmax,*ppre;
if(head==NULL) return 0;
else {
while(head->next!=NULL) {
p=pmax=ppre=head;
while(p->next!=NULL) {
if(p->next-> birth[0] > pmax->birth[0]) {
pmax=p->next;
ppre=p;
}
p=p->next;
}
if(head==pmax) {
head=head->next;
pmax->next=NULL;
} else {
ppre->next=pmax->next;
pmax->next=NULL;
}
if(pnew==NULL) {
pnew=pmax;
} else {
pmax->next=pnew;
pnew=pmax;
}
}
head->next=pnew;
pnew=head;
return head;
}
}
char menu() {
system("cls");
char ch;
cout<<"\n\n";
cout<<" ******************新生信息统计****************\n";
cout<<" 1.新建学生档案";
cout<<" 2.增加学生信息\n";
cout<<" 3.删除信息";
cout<<" 4.查询信息\n";
cout<<" 5.修改信息";
cout<<" 6.展示信息\n";
cout<<" 7.读档";
cout<<" 8.保存并退出\n";
cout<<" **********************************************\n";
cin>>ch;
return ch;
}
int main ()
{
Studentmanage s;
Student *head;
head=NULL;
int n=0;
char c;
cout<<"\t\t\t欢迎新生报到!\n\n\n";
cout<<"\t\t 渗透一班 刘华辉\n";
cout<<"\n\n\n\n\n\n";
system("pause");
while(1)
switch (menu()) {
case'1':
head=s.creat();
system("pause");
break;
case'2':
head=s.add(head);
system("pause");
break;
case'3':
head=s.delet(head);
system("pause");
break;
case'4':
s.search(head);
system("pause");
break;
case'5':
head=s.modify(head);
system("pause");
break;
case'6':
s.sort(head);
s.display(head);
system("pause");
break;
case'7':
head=s.read_file();
s.display(head);
system("pause");
break;
case'8':
s.write_file(head);
cout<<"谢谢使用!再见!\n";
system("pause");
return 0;
default:
cout<<"选择有错,请重新选择\n";
}
return 0;
}