工资管理课程设计报告.docx
《工资管理课程设计报告.docx》由会员分享,可在线阅读,更多相关《工资管理课程设计报告.docx(24页珍藏版)》请在冰点文库上搜索。
![工资管理课程设计报告.docx](https://file1.bingdoc.com/fileroot1/2023-5/25/94f95c86-569d-4f8a-a24e-28bf447903e1/94f95c86-569d-4f8a-a24e-28bf447903e11.gif)
工资管理课程设计报告
南京理工大学VC++课程设计报告
课程:
VC++课程设计
系别:
班级:
选题2名称:
工资管理
选题2难易级别:
A级
自报成绩:
日期:
2012年10月19日
目录
一、课题目标
1-1程序功能简介
1-2课程设计要求
1-3评定难易级别
二、具体实现
2-1开发平台
2-2源程序主函数结构流程图
2-3基本类及主要函数
2-3-1基本类
2-3-1-1工资数据类
2-3-1-2结点类
2-3-1-3链表类
2-3-2主要函数
2-3-2-1数据的录入
2-3-2-2数据按姓名查找
2-3-2-3数据的显示
2-3-2-4删除链表
2-3-2-5插入新节点
2-3-2-6数据文件的存取
2-3-2-7增加数据
三、调试报告
(在设计和实现过程所遇到的问题和解决)
四、总体小结
(在整个设计过程中的心得体会)
五、分工介绍
(是独立完成还是合作完成)
一、课题目标
1-1:
程序功能简介:
这是一个员工工资管理程序。
工资管理的数据文件中存储有员工姓名和工资,该程序可以录入、显示、查找、修改、删除员工的姓名和工资。
1-2课程设计要求:
(1)用类的形式改写程序,将程序中工资数据用链表的形式存放,定义一个链表类,封装主要的操作函数。
(2)显示、修改、删除数据项时大小写通用。
(3)工资数据按照工资值的大小进行排序存放。
(4)修改,删除数据前增加提示信息,用户确认后才能进一步的修改及删除操作,否则取消操作。
(5)增加程序的文件输入输出功能,在执行程序中首先将工资数据从文件中读出来再进行管理,在程序结束时能将工资数据保存在原文件中。
1-3评定难易级别
A级
二、具体实现
2-1、开发平台
操作系统:
Windows7
开发工具VC++6.0
2-2、源程序主函数结构流程图
N
Y
Y
N
N
Y
0-
1
3
4-
5-
2
2-3、基本类及主要函数
2-3-1-1工资数据类
classSalary//定义一个工资的类,用于描述节点的数据信息
{
private:
charcName[20];//用于存放员工姓名
doubledSalary;//用于存放员工薪水数据
public:
Salary()//定义缺省的构造函数
{
strcpy(cName,"\0");
dSalary=0.0;
}
Salary(char*name,doublesalary)//定义有参数的构造函数
{
strlwr(name);
strcpy(cName,name);
dSalary=salary;
}
voidSetSalary(char*name,doublesalary);//置相关数据的值
char*GetName();//返回对象中员工名字
doubleGetSal();//返回对象中员工的薪水
intCompare(Salary&s);
voidShow()//输出数据
{
cout<"<}
};
2-3-1-2结点类
classNode//定义一个结点类
{
private:
Salary*pData;//描述结点的数据域
Node*pNext,*prew;//构成链表的前后向指针
public:
Node()//缺省的构造函数,置结点的
{
pData=0;
pNext=prew=0;
}
Node(Node&node)//完成拷贝功能的拷贝构造函数
{
pData=node.pData;
pNext=node.pNext;
prew=node.prew;
}
voidInputData(Salary*pSal)//使得结点的数据域指针指向某数据
voidShowNode()//展示结点数据
Salary*GetData()//返回指向结点的数据域的指针
voidSetData(Salary*p)//改变结点的数据域
Node*GetNext()//返回下一个结点的地址
voidSetNext(Node*p)//置结点中的向后指针
voidSetprew(Node*p)//置结点中的向前指针
friendclassList;//定义友元类
};
2-3-1-3链表类
classList//定义链表类,实现双向链表操作
{
protected:
Node*pHead,*pTail;//链表首指针和链表尾指针
public:
List(){pHead=NULL,pTail=NULL;}//缺省的构造函数,置首尾指针为NULL
~List(){DeleteList();}//析构函数
voidAddNode(Node*pnode)//增加一个节点,直接加在链首
voidDeleteNode(Node*p)//删除某结点
Node*LookUp(Salary&s)//在链表中搜索某个指定的结点
voidShowList()//按照从链表首到尾,输出链表数据成员
voidDeleteList()//删除链表
Node*GetListHead()//返回链表首指针
Node*GetListNextNode(Node*n)//返回指向下一个结点的指针
voidSetListHead(Node*p)//置结点头指针
intInsert(Node*p)//插入一个节点
intPrintList()//输出到文件
};
主要功能及其实现函数
2-3-2-1数据的录入
voidSetSalary(char*name,doublesalary)//置姓名与工资的值
{
strlwr(name);
strcpy(cName,name);
dSalary=salary;
}
char*GetName()//返回对象中员工名字
{
returncName;
}
doubleGetSal()//返回对象中员工的薪水
{
returndSalary;
}
intCompare(Salary&s)
{
if(strcmp(cName,s.cName))
{
return0;
}
else
{
return1;
}
}
voidShow()//输出数据
{
cout<<"员工"<"<}
};
2-3-2-2数据按姓名查找
Node*LookUp(Salary&s)//在链表中搜索某个指定的结点
{
Node*p1,*p2;
if(pHead==NULL)
{cout<<"~~~~(>_<)~~~~数据不存在!
"<returnNULL;
}
if(pHead->pData->GetSal()==s.GetSal())
{returnpHead;
}
else
{
p2=p1=pHead;
while(p2->pData->GetSal()!
=s.GetSal()&&p2->pNext!
=NULL)
{p1=p2;
p2=p2->pNext;
}
if(p2->pData->GetSal()==s.GetSal())
{returnp2;
}
else
{
cout<<"没有找到相应数据!
"<returnNULL;
}
}
}
2-3-2-3数据的显示
voidShowList()//按照从链表首到尾,输出链表数据成员
{
cout<<"***************************"<Node*p=pHead;
while(p!
=NULL)
{
p->ShowNode();
p=p->pNext;
}
cout<cout<<"***************************"<cout<}
2-3-2-4删除链表
voidDeleteList()//删除链表
{
Node*p;
while(pHead!
=NULL)
{
p=pHead;
pHead=pHead->pNext;
deletep;
}
}
2-3-2-5插入新节点
intInsert(Node*p)//插入一个结点
{
Node*p1,*p2;
if(pHead==NULL)//条件成立时,为空链表
{
p->pNext=NULL;
p->prew=NULL;
pHead=p;//使链首和链尾指针指向该结点
pTail=p;
return0;
}
if(pHead->pData->GetSal()>=p->pData->GetSal())//第一个数大于新插入数,直接插到头结点
{
pHead->prew=p;
p->pNext=pHead;
p->prew=NULL;
pHead=p;//直接将该结点加入链首,并改变链首的指针值
return0;
}
p1=p2=pHead;
while(p2->pNext&&p2->pData->GetSal()pData->GetSal())//依次查找,确定结点位置
{
p1=p2;
p2=p2->pNext;
}
if(p2->pData->GetSal()pData->GetSal())//数据为最大时
{
p->prew=p2;
p2->pNext=p;
p->pNext=NULL;
pTail=p;//直接将该结点加在链尾
}
else//"else"代表该结点应该插入链表中间的某个位置
{
p2->prew=p;
p->pNext=p2;
p->prew=p1;
p1->pNext=p;
}
return0;
}
2-3-2-6数据文件的存取
intPrintList()
{
charfilename[255];
cin.ignore();
cin.getline(filename,254);
ofstreamoutfile(filename);//以写方式打开filename的文件
if(!
outfile)//判断是否打开成功
{
cout<<"打开源文件失败,不能打开源文件。
"<return0;
}
Node*p=pHead;
while(p!
=NULL)//判断是否已经到达链尾,将链表上的数据输入到文件中
{
outfile<GetData()->GetName()<<'\n';
outfile<GetData()->GetSal()<<'\n';
p=p->GetNext();
}
outfile.close();//关闭文件
return0;
}
intGetList()//从文件中输出(无论初次文件中的数据是否有顺序)
{
charfilename[255];
cout<<"请输入文件名:
"<Node*p=0;
Salary*s;
cin.ignore();
cin.getline(filename,254);
ifstreaminfile(filename,ios:
:
in);//以读方式打开文件filename
if(!
infile)//判断是否打开成功
{
cout<<"不能打开源文件."<return0;
}
charname[20],ch;
doublesal;
p=newNode;
s=newSalary;
pHead=pTail=NULL;
while(infile.getline(name,20))//判断是否已经取完数据,满足条件则进行循环
{
infile>>sal;
s->SetSalary(name,sal);
p->SetData(s);
Insert(p);
infile.get(ch);//读取文件流中的一个换行符
p=newNode;
s=newSalary;
}
deletep;
deletes;
infile.close();
cout<<"读取文件成功!
"<cout<return0;
}
voidDeleteFirNode()
{
Node*p=pHead;
pHead=pHead->GetNext();
deletep;
}
};
2-3-2-7增加数据
voidAddRecord(List&SalaryList)//增加某结点,即增加工资记录
{
Node*pNode;
Node*p1,*p2;
Salary*pSal;
charcName[20];
charstr[100];
doubledPlaceSalary;
cout<<"请输入姓名(输入0结束):
";
cin.ignore();
cin.getline(cName,20);
while(strcmp(cName,"0"))//判断是否结束增加
{
charflag1;
pNode=newNode;
pSal=newSalary;
pSal->SetSalary(cName,0);
Node*hd;
hd=SalaryList.GetListHead();//将hd指向链表
if(hd==NULL)//判断链表是否为空
{
cout<<"请输入工资:
";
cin>>dPlaceSalary;
while(!
cin)//判断是否输入成功
{
cin.clear();//重置状态字state中的二进制位
cin.getline(str,100);//将流中的错误数据清除
cout<<"非法输入,请输入正确工资数据:
"<cin>>dPlaceSalary;
}
pSal->SetSalary(cName,dPlaceSalary);//将psal指向的对象设置数据
pNode->InputData(pSal);//置结点的数据域
SalaryList.Insert(pNode);//将结点插入到链表中
cout<<"请输入姓名(输入0结束):
";
cin.ignore();
cin.getline(cName,20);
continue;//结束本轮循环,直接进行判断进入下一轮的循环
}
if(hd->GetData()->Compare(*pSal))//判断增加的结点的名称是否存在(此次判断是是否存在于链首)
{
cout<<"您输入的名字数据库中已存在,是否重新输入其工资数据?
选Y或y为是,其它任意键为否"<cin>>flag1;
if((flag1=='y')||(flag1=='Y'))
{
cout<<"请输入工资:
";
cin>>dPlaceSalary;
while(!
cin)
{
cin.clear();
cin.getline(str,100);
cout<<"非法输入,请输入正确工资数据:
"<cin>>dPlaceSalary;
}
hd->GetData()->SetSalary(cName,dPlaceSalary);
cout<<"请输入姓名(输入0结束):
";
cin.ignore();
cin.getline(cName,20);
}
else
{
cout<<"请输入姓名(输入0结束):
";
cin.ignore();
cin.getline(cName,20);
}
}
else
{
p2=p1=hd;
while(p2->GetData()->Compare(*pSal)==0&&p2->GetNext()!
=NULL)//搜索链表中是否有与其姓名一样的数据
{
p1=p2;
p2=p2->GetNext();
}
if(p2->GetData()->Compare(*pSal))//判断在增加的数据的姓名是否已经存在,满足条件则存在
{
cout<<"您输入的名字数据库中已存在,是否重新输入其工资数据?
选Y或y为是,其它任意键为否"<cin>>flag1;
if((flag1=='y')|(flag1=='Y'))
{
cout<<"请输入工资:
";
cin>>dPlaceSalary;
while(!
cin)
{
cin.clear();
cin.getline(str,80);
cout<<"非法输入,请输入正确工资数据:
"<cin>>dPlaceSalary;
}
p2->GetData()->SetSalary(cName,dPlaceSalary);
}
cout<<"请输入姓名(输入0结束):
";
cin.ignore();
cin.getline(cName,20);
}
else//else说明输入的数据的名称在链表中不存在
{
cout<<"请输入工资:
";
cin>>dPlaceSalary;
while(!
cin)
{
cin.clear();
cin.getline(str,80);
cout<<"非法输入,请输入正确工资数据:
"<cin>>dPlaceSalary;
}
pSal->SetSalary(cName,dPlaceSalary);
pNode->InputData(pSal);
SalaryList.Insert(pNode);
cout<<"请输入姓名(输入0结束):
";
cin.ignore();
cin.getline(cName,20);
}
}
}
cout<}
三、调试报告
问题1:
显示、修改、删除数据时,大小写通用问题
解决方法:
所有从文件(磁盘文件与外设文件)中读取的数据都先经过strlwr(char*)的处理,才会进入链表中,输出数据时都以小写输出。
问题2:
在选择删除时,一定会显示工资最低的人的信息
经检验,由于某次输入时光标位置错误,导致代码输错行,此次充分体现了细心的重要性。
问题3:
需要读取的文件中的数据不是按照一定的从小到大(或从大到小)排列,读取文件时如何建立有序链表。
解决方法:
每一个数据读入时,都按照插入链表的形式加入到链表中,而非简单的接在链尾,这样原文件中无序的数据读入链表时,就已经是有序的了。
问题4:
打开关闭文件时有错误:
一开始发现在开始欢迎界面上,选择打开已有链表后,就算输入不存在的文件名,都提示“读取文件成功”
解决方法:
因为刚刚学的文件操作,不是很熟悉,在研究了课本后发现问题出在这里ifstreaminfile(filename,ios:
:
in);这里缺少一个只能打开已存在文件的限定,将其改为
ifstreaminfile(filename,ios:
:
in|ios:
:
nocreate);后问题解决了。
四、总体小结
不要一味追求速度,在追求编写速度提高的同时,出现错误的可能性也大大提高,而编写时节省下来的时间远远比不上改错用的时间;书写要尽量清晰,加注解很重要,方便阅读和找出错误;方法很重要,能帮助减少书写量,程序运行效率也更高;注意细节,对临界值确定一定要小心,很可能出现错误。
为了及时找出错误,我将写的初级版程序打印出来,方便熟悉它以及更多思考它的不足。
事实证明,大量的心力投入是程序较完善的重要前提。
由此我懂得了,做任何事,只要付出不是百分之百,那么后果多将有可能是我们所不能承受的。
因此在以后的日子里,我在做事时都将更认真,更投入。
五分工介绍
独立完成