资源描述
数据结构课程设计
数据结构
课程设计报告
学院:信息科学与工程学院
班级:通信工程1301班
题目:活期储蓄帐目管理系统
指导老师:康松林
完成日期:2015年7月16日
0
目录
一、问题描述与基本要求 1
1.1问题描述 1
1.2基本要求 1
二、数据结构的设计 1
2.1数据结构的选择 1
2.2单链表的定义 2
2.3重要函数的定义及说明 2
三、软件模块结构图 6
3.1大体模块关系图 6
3.2各模块具体分析 7
四、程序流程图 8
五、源程序 11
六、调试分析 16
6.1程序错误修改及完善的过程 16
6.2最终程序所有功能运行结果 20
6.3测试数据 22
七、用户使用手册 23
八、心得体会 23
一、问题描述与基本要求
1.1问题描述
设计一个活期储蓄帐目管理系统
活期储蓄处理中,储户开户、销户、存入、支出活动频繁。
1.2基本要求
系统设计要求:
1、能比较迅速地实现插入,以实现储户开户的功能,储户开户时需输入的信息包括储户姓名,密码。
2、能比较迅速地通过储户的账户序号和密码找到储户的账户,并删除该账户,以实现销户的功能。
3、能比较迅速地通过储户的账户序号和密码找到储户的账户(密码不对时,可选择是否重新输入密码)实现账户登录的功能。登录成功后,再通过修改链表结点数据域中的对应元素,以实现存款、取款、显示余额等功能,若取款时账户余额不足,输出提示信息“取款失败!你账户上的金额不足!”,并显示账户当前余额,并且提示重新输入合适的取款金额。
4、查找活期储蓄帐目管理系统当前存在的储户,当输出活期储蓄帐目管理系统没有账户时,输出提示信息“活期储蓄帐目管理系统没有账户”,当有账户时,输出所有账户的相关信息,包括储户姓名,帐号,密码,账户余额。
二、数据结构的设计
2.1数据结构的选择
课程设计题目的要求是,要较简单迅速地实现开户、销户、存款、取款、输出用户信息的功能,于是我很自然地想到了可以用单链表的结构,通过编写相应功能函数来实现建立新结点、删除结点、修改结点中数据域的内容、输出结点数据域中的内容等功能,即可满足课程设计题目的要求。
2.2单链表的定义
先定义单链表结点的数据域,数据域包括储户姓名、账户序号、账户密码、账户金额等储户信息,然后再定义链表结点,链表结点包括结点数据域和结点链域,最后再定义指向链表结点的指针。以下为单链表的相关定义:
typedef struct ListData //定义结点数据域
{
char name[3]; //储户姓名
int account; //账户序号
char password[5]; //账户密码
int money; //账户金额
}ListData;
typedef struct node //定义链表结点
{
ListData data; //结点数据域
struct node *next; //结点链域
}ListNode;
typedef ListNode *LinkList; //指向链表结点的指针
2.3重要函数的定义及说明
1、 void InitList (LinkList &L) //建立空链表
2、void InsertList (LinkList &L) //插入链表结点,实现开户功能
(需要输入储户姓名和密码,以确定开户对象)
3、 void DeleteList (LinkList &L) //删除链表结点,实现销户功能
(需要输入账号和密码,以确定销户对象)
4、void Deposit (LinkList &L,LinkList p) //储户存款、取款、显示余额(要先通过账号和密码登录,若取款时账户余额不足,输出提示信息,显示账户当前余额,并且提示重新输入取款金额。)
5、void Search (LinkList L) //链表查找,实现用户登录功能
(需要输入账号和密码,以确定登录对象,密码输出错误时可选择是否重新输入密码)
6、 void PrintList (LinkList L) //输出链表,实现储户姓名,账号序号,密码,现有余额等相关信息。(当输出活期储蓄帐目管理系统没有账户时,输出提示信息,当有账户时,输出所有账户的相关信息。)
以下为重要函数的定义:
void InitList(LinkList &L) //建立空链表
{
L=(ListNode*)malloc (sizeof(ListNode));
L->next=NULL;
}
void InsertList(LinkList &L) //链表插入结点,实现开户功能,需输入储户姓名和密码
{
LinkList p;
p=(ListNode*)malloc(sizeof(ListNode));
printf("请输入你要开户的姓名(不超过4个字符):");
scanf("%s",p->data.name);
number=number+1;
p->data.account=number;
printf("你开户的账号为:%d\n",p->data.account);
printf("请输入你账号的密码(不超过6个字符):");
scanf("%s",p->data.password);
p->data.money=0;
p->next=NULL;
if(L->next==NULL) //前插法
L->next=p;
else
{
p->next=L->next;
L->next=p;
}
printf("开户成功!\n");
}
void DeleteList(LinkList &L) //删除链表结点,实现销户功能(需要输入账号和密码)
{
LinkList p=L,q;
char mima[5];
int s;
printf("请输入你要销户的账号:");
scanf("%d",&s);
printf("请输入该账号的密码:");
scanf("%s",mima);
while(p->next!=NULL)
{
if(p->next->data.account==s)
break;
p=p->next;
}
if(p->next!=NULL)
{
while(strcmp(p->next->data.password,mima)!=0)
{
printf("密码错误!请重新输入:");
scanf("%s",mima);
}
q=p->next;
p->next=q->next;
free(q);
printf("销户成功。\n");
}
else printf("你所要销户的的账号不存在。\n");
}
void Deposit(LinkList &L,LinkList p) //储户存款、取款、显示余额
{
int m;
int n;
while(1)
{
if(p!=NULL)
{
printf("\n请输入数字选择功能:1、存款 2、取款 3、查询余额 4、退出账号 :");
scanf("%d",&m);
if(m==1)
{
printf("请输入你的存款金额:");
scanf("%d",&n);
p->data.money=p->data.money+n;
printf("存款成功!\n");
}
else if(m==2)
{
printf("请输入你的取款金额:");
gg:
scanf("%d",&n);
if((p->data.money-n)>=0)
{
p->data.money=p->data.money-n;
printf("取款成功!\n");
}
else
{
printf("取款失败!你账户上的金额不足!\n");
printf("你的账户余额为:%d\n",p->data.money);
printf("请输入合适的取款金额:");
goto gg;
}
}
else if(m==3)
{
printf("你账户的余额为:%d\n",p->data.money);
}
else if(m==4)
{
printf("账号退出成功。\n");
return;
}
}
}
}
void Search(LinkList L) //链表查找,实现用户登录功能(需要输入账号和密码)
{
LinkList p=L->next;
int i;
char mima[5];
printf("请输入你要登录的账号:");
scanf("%d",&i);
tt: printf("请输入你的密码:");
scanf("%s",mima);
while(p!=NULL)
{
if(p->data.account==i)
break;
p=p->next;
}
if(p==NULL)
printf("不存在该账户\n");
else
{
if(strcmp(p->data.password,mima)==0)
printf("登录成功。\n");
else
{
while(strcmp(p->data.password,mima)!=0)
{
char j;
printf("密码错误\n");
printf("是否重新输入(是,从键盘输入Y )、(否,从键盘上输入N ):");
scanf("\n%c",&j);
if(j=='N')
{return;}
else if(j=='Y')
{goto tt;}
}
}
Deposit(L,p);
}
}
void PrintList(LinkList L) //输出链表,实现储户信息输出
{
LinkList p=L->next;
if(p==NULL)
{
printf("活期储蓄帐目管理系统没有账户\n");
}
else printf("姓名 帐号 密码 账户余额\n");
while(p!=NULL)
{
printf("%s\t",p->data.name);
printf("%d\t%s\t\t%d\n",p->data.account,p->data.password,p->data.money);
p=p->next;
}
printf("请先输入enter键,再重新选择功能\n");
}
三、软件模块结构图
主函数
链表插入模块
链表删除模块
链表查找、存款、取款模块
链表显示模块
3.1大体模块关系图
3.2各模块具体分析
链表插入模块具体分析如下:
InsertList(L)
scanf( )
p->data.name
p->data.password
链表删除模块具体分析如下:
DeleteList(L)
scanf( )
s,mima
Search(L)
scanf( )
i,mima,j
m,n
Deposit(L,p)
p->data.money
链表查找、存款、取款模块具体分析如下:
链表输出模块具体分析如下:
PrintList(L)
p->data.name,p->data.passwordp->data.account,p->data.money
printf( )
注:以上具体分析中,无箭头的线段表示函数的调用关系,椭圆中的数据为输入、输出或传递的值,箭头表示值的方向。
四、程序流程图
A
B
C
D
……
……
……
……
1
2
3
4
结束
输入1,InsertList(L)用户开户
输入2,DeleteList(L)用户销户
输入3,Search(L)存款、取款显示余额。
输入4,PrintList(L)输出储户信息
输入5,退出管理系统
InitList(L)
功能表与编号选择1-5
输入数字,选择功能
主函数main( )
开始
^
注:因为整个程序流程图太长,一页画不下,所以上图为大体流程图,上图中1—>A,2—>B,3—>C,4—>D间流程省略了,以下为1—>A,2—>B,3—>C,4—>D间详细流程图。
1
输入开户姓名
输入开户密码
开户成功
A
1—>A
是
是
否
否
销户成功
B
输入账户密码
密码是否正确?
你所要销户的的账号不存在
账户是否存在
2
输入销户账号
2
2
2—>B
输入销户账号
输入销户账号
存款成功
重新输入取款金额
是
否
是
否
是
是
否
输入1后,输入存款金额
输入2后,输入取款金额
输入3,显示当前余额
C
取款金额>=余额?
取款成功
输入1-4,选择功能
输入4,退出账户
退出登录
密码是否正确?
登录成功
是否重新输入密码
Deposit(L,p)
输入账户密码
3
输入要登录的账号
账户是否存在?
不存在该账号
C
3
3
3—>C
输入要登录的账号
输入要登录的账号
不存在该账号
账户是否存在?
账户是否存在?
不存在该账号
输入账户密码
C
C
4—>D
是
输出姓名、帐号、密码、账户余额
p=p->next
4
p==NULL?
管理系统没有账户
是
否
p==NULL?
否
D
五、源程序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int number=0; //定义的全局变量,用于开户
typedef struct ListData //定义结点数据域
{
char name[3]; //储户姓名
int account; //账户序号
char password[5]; //账户密码
int money; //账户金额
}ListData;
typedef struct node //定义链表结点
{
ListData data; //结点数据域
struct node *next; //结点链域
}ListNode;
typedef ListNode *LinkList; //指向链表结点的指针
void InitList(LinkList &L) //建立空链表
{
L=(ListNode*)malloc (sizeof(ListNode));
L->next=NULL;
}
void InsertList(LinkList &L) //链表插入结点,实现开户功能,需输入储户姓名和密码
{
LinkList p;
p=(ListNode*)malloc(sizeof(ListNode));
printf("请输入你要开户的姓名(不超过4个字符):");
scanf("%s",p->data.name);
number=number+1;
p->data.account=number;
printf("你开户的账号为:%d\n",p->data.account);
printf("请输入你账号的密码(不超过6个字符):");
scanf("%s",p->data.password);
p->data.money=0;
p->next=NULL;
if(L->next==NULL) //前插法
L->next=p;
else
{
p->next=L->next;
L->next=p;
}
printf("开户成功!\n");
}
void DeleteList(LinkList &L) //删除链表结点,实现销户功能(需要输入账号和密码)
{
LinkList p=L,q;
char mima[5];
int s;
printf("请输入你要销户的账号:");
scanf("%d",&s);
printf("请输入该账号的密码:");
scanf("%s",mima);
while(p->next!=NULL)
{
if(p->next->data.account==s)
break;
p=p->next;
}
if(p->next!=NULL)
{
while(strcmp(p->next->data.password,mima)!=0)
{
printf("密码错误!请重新输入:");
scanf("%s",mima);
}
q=p->next;
p->next=q->next;
free(q);
printf("销户成功。\n");
}
else printf("你所要销户的的账号不存在。\n");
}
void Deposit(LinkList &L,LinkList p) //储户存款、取款、显示余额
{
int m;
int n;
while(1)
{
if(p!=NULL)
{
printf("\n请输入数字选择功能:1、存款 2、取款 3、查询余额 4、退出账号 :");
scanf("%d",&m);
if(m==1)
{
printf("请输入你的存款金额:");
scanf("%d",&n);
p->data.money=p->data.money+n;
printf("存款成功!\n");
}
else if(m==2)
{
printf("请输入你的取款金额:");
gg:
scanf("%d",&n);
if((p->data.money-n)>=0)
{
p->data.money=p->data.money-n;
printf("取款成功!\n");
}
else
{
printf("取款失败!你账户上的金额不足!\n");
printf("你的账户余额为:%d\n",p->data.money);
printf("请输入合适的取款金额:");
goto gg;
}
}
else if(m==3)
{
printf("你账户的余额为:%d\n",p->data.money);
}
else if(m==4)
{
printf("账号退出成功。\n");
return;
}
}
}
}
void Search(LinkList L) //链表查找,实现用户登录功能(需要输入账号和密码)
{
LinkList p=L->next;
int i;
char mima[5];
printf("请输入你要登录的账号:");
scanf("%d",&i);
tt: printf("请输入你的密码:");
scanf("%s",mima);
while(p!=NULL)
{
if(p->data.account==i)
break;
p=p->next;
}
if(p==NULL)
printf("不存在该账户\n");
else
{
if(strcmp(p->data.password,mima)==0)
printf("登录成功。\n");
else
{
while(strcmp(p->data.password,mima)!=0)
{
char j;
printf("密码错误\n");
printf("是否重新输入(是,从键盘输入Y )、(否,从键盘上输入N ):");
scanf("\n%c",&j);
if(j=='N')
{return;}
else if(j=='Y')
{goto tt;}
}
}
Deposit(L,p);
}
}
void PrintList(LinkList L) //输出链表,实现储户信息输出
{
LinkList p=L->next;
if(p==NULL)
{
printf("活期储蓄帐目管理系统没有账户\n");
}
else printf("姓名 帐号 密码 账户余额\n");
while(p!=NULL)
{
printf("%s\t",p->data.name);
printf("%d\t%s\t\t%d\n",p->data.account,p->data.password,p->data.money);
p=p->next;
}
printf("请先输入enter键,再重新选择功能\n");
}
void main()
{
LinkList L;
InitList(L);
printf(" ************************************************************\n");
printf(" 欢迎进入活期储蓄账目管理系统,以下是相关功能及编号: \n");
printf(" 1.储户开户(输入储户姓名,密码) \n");
printf(" 2.储户销户(输入账户序号,密码) \n");
printf(" 3.储户的账号存款、取款、余额查询 \n");
printf(" 4.查看所有储蓄账户信息(输出储户姓名,帐户序号,密码,账户余额)\n");
printf(" 5.退出账目管理系统 \n");
printf(" ************************************************************\n");
char j;
hh:
printf("\n请选择你需要的功能:");
scanf("%c",&j);
getchar();
if(j>'5')
printf("输入有误,请重新选择操作:\n");
if(j=='5')
{printf("您将退出账目管理系统!\n");
exit(0);}
switch(j)
{
case '1':InsertList(L);getchar();break;
case '2':DeleteList(L);getchar();break;
case '3':Search(L);getchar();break;
case '4':PrintList(L);getchar();break;
default:break;
}
goto hh;
}
六、调试分析
6.1程序错误修改及完善的过程
我这次的课程设计题目是根据我的学号选择的,当看到这个题目时,我觉得还算比较简单,因为我之前数据结构实验就做过单链表的插入、删除、查找、输出,而这次活期储蓄帐目管理系统要求的开户、销户、存款、取款、输出储户信息等功能,即可用单链表的相关功能函数来实现,于是我修改了之前写过的单链表的一些函数,以满足这次题目的要求,但在实验过程中仍出现了一些错误。最终经过我的仔细检查和修改,最终编写出了符合要求的程序,还增加了一些功能。
1、由于之前编写过类似程序,所以写完程序后很快就可以运行了,但是运行结果存在问题,比如创建的新用户的账户序号不是从1按顺序递增的,而是永远是1,不会改变,错误如下图所示:
我仔细检查了一下InsertList函数的定义,意识到了错误所在,我原本以为用“p->data.account=0;p->data.account++;”这两条语句就可以达到开户时账户序号递增的目的,后来才意识到这样编写程序,每次新建用户都是重新赋0值,再自加,结果完全不对。于是我定义了一个全局变量int number=0,然后将原来的“p->data.account=0;p->data.account++”“number=number+1;p->data.account=number;”运行后得到了如下的正确的结果:
2、我编写完程序后,觉得程序太过简单,又想到题目是活期储蓄帐目管理系统,那账户应该是有密码保证安全性的,于是我又在单链表结点的数据域中加入了一个新的元素password[5],并且还修改了后面相关函数的定义,确保在销户时,必须账户序号和密码相对应时才能销户成功,在存款、取款时也只有当账户序号和密码相对应时才能登录成功,选择存款、取款或显示余额等功能。因此,函数定义中除了密码正确时的相关操作,还应有密码错误时的提示信息和相关操作。于是,我在DeleteList函数和Search函数中加入了判断p->data.password与mima是否相等的语句,重要语句如下:
DeleteList函数定义中:
Search函数定义中:
修改了相关函数定义后,调用程序,又出现了如下错误:error C2065: 'strcmp' : undeclared identifier,我才意识到我在DeleteList函数和Search函数的定义中调用了strcmp函数,头文件中应包括#include<string.h>,加上后运行结果就对了。
修改后,相关调试结果如下:
3、 再次修改完程序后,我希望程序还能更加完善,于是我开始思考出了密码与账户不对应,导致销户失败和登录失败外,还可能出现哪些其他的特殊情况。于是我又想到了两个特殊情况,一是取款时,账户余额可能不够,则应该输出提示信息,告知用户当前账户余额,并要求用户输入合适的取款金额。二是,可能系统没有建立账户,或者是建立了账户但是已经销户,就会导致当前系统没有账户,输出账户信息为空,这时就需要输出提示信息“活期储蓄帐目管理系统没有账户”,于是我根据自己的想法又对程序做了一些修改,修改的重要语句如下:
Deposit函数定义中:
PrintList函数定义中:
程序修改后调试结果如下:
6.2最终程序所有功能运行结果
图一:
图二:
图三:
图四:
图五:
6.3测试数据
图一(开户功能):成功开两个新账户,分别为
账号:1,姓名:lsm,密码:asdfgh;
账号:2,姓名:王晓珂,密码:qwerty。
图二(存取款前的登录功能):选择登录账号1,
输入了错误密码asdfgf,
重新输入密码asdfgh,密码正确,登录成功。
图三(存取款功能):存款1000,存款成功;
取款2000(超过余额1000),取款失败;
重新输入取款金额800,取款成功;
查询余额200;
退出登录。
图四(显示功能):显示当前活期储蓄帐目管理系统中储户相关信息,分别为
姓名:wxk,账号:2,密码:qwerty,账户余额:0;
姓名:lsm,账号:1,密码:asdfgh,账户余额:200。
图五(销户功能):删除账号2(需密码登录),销户成功;
系统只剩下账号1,输出账号1相关信息。
七、 用户使用手册
本系统是活期储蓄帐目管理系统,该系统可以比较快速地实现开户、销户、查询、存款、取款等多种功能。进入本系统后,随即显示系统主菜单页面,用户可在该界面下根据提示输入各子菜单前对应的数字并按回车键,执行相应子菜单命令。
用户使用该系统流程如下:
第一步:运行程序,显示系统主菜单页面,数字1—5表示不同功能,1.储户开户(输入储户姓名,密码),2.储户销户(输入账户序号,密码),3.储户的账号存款、取款、余额查询 ,4.查看所有储蓄账户信息(输出储户姓名,帐户序号,密码,账户余额), 5.退出账目管理系统。
第二步 :输入合适数字选择对应功能。
第三步:选择功能后,按照子菜单提示继续进行操作,直到实现相关功能。
第四步:实现了相关功能后,可以重新选择功能,重复第二步和第三步,也可选择退出系统。
八、 心得体会
因为这次的课程设计题目与之前上机做过的单链表数据结构实验类似,所以当我看到这个题目时,不是很紧张,而是有一定的思路和信心。于是我找到了之前编写过的类似程序,在其基础上做了修改和完善,最后完成了这次数据结构课程设计。当然,在这个过程中,也遇到了一些错误,但是我没有心烦气躁,而是仔细琢磨程序,思考到底是哪里出了问题,又应该如何修改,最终在我的不懈努力下,我实现了题目要求的功能,还添加了一些其他的功能,自己有了一定的成就感和满足感。
总而言之,在这次过程中,我有很多的收获与体会。通过这次数据结构课程设计,我不仅变得更加细心了,而且对课本知识也理解得更透彻,深刻理解了单链表的插入、删除、查找和输出,还学会了如何将书本知识运用到实际生活中去,让我对学习数据结构这门课又多了一份兴趣和信心。
23
展开阅读全文