《个人账单管理系统数据结构课程设计.doc》由会员分享,可在线阅读,更多相关《个人账单管理系统数据结构课程设计.doc(22页珍藏版)》请在三一办公上搜索。
1、沈阳航空航天大学课 程 设 计 报 告课程设计名称:数据结构课程设计课程设计题目:个人账簿管理系统目 录沈阳航空航天大学I1 课程设计介绍11.1 课程设计内容11.2 课程设计要求12 课程设计原理22.1 课设题目粗略分析22.2 原理图介绍22.2.1 功能模块图22.2.2 流程图分析33 数据结构分析73.1 存储结构73.2 算法描述74.1 调试过程164.2程序执行过程16参考文献19 1 课程设计介绍1.1 课程设计内容 个人账簿管理系统记录某人每月的全部收入及各项开支情况,包括食品消费,房租,子女教育费,水电费,医疗费,储蓄等。进入系统后可以输入和修改某月的收支情况,可以对
2、每月的开支从小到大进行排序,可以根据输入的月份查询每月的收支情况。1.2 课程设计要求1. 采用链表结构管理收支情况,并能够保存到文件中;2. 完成对每月的开支排序,以及完成系统查询功能;3. 独立完成系统的设计,编码和调试;4. 系统利用C语言实现;5. 按照课程设计规范书写课程设计报告。2 课程设计原理2.1 课设题目粗略分析根据课设题目要求,拟将整体程序分为五大模块。以下是五个模块的大体分析:1. 账簿信息输入:该模块中,以带头结点的链表为账单信息的存储结构,输入各项开支的数据。2. 账簿信息排序:该模块中,将针对每月的消费总额进行从小到大的顺序进行排序。3. 账簿信息查询:该模块中,将
3、输入或已排序账单进行按所输入的日期进行查询并将查询结果打印至屏幕,供人阅读。4. 账单信息更改:进入该模块,进行信息的更改或添加。5. 账单信息保存:该模块将账单信息以文本文档保存到磁盘中。2.2 原理图介绍2.2.1 功能模块图图2.1功能模块图2.2.2 流程图分析1. 账单建立时调用jianli()函数,而在在jianli()中调用tianjia()函数;账单的头结点的申请工作已在主函数中完成,所以在整个建立账单的过程中核心内容是:将新的账单信息链接到已存在的账单后面;tianjia()函数流程图如图2.2所示。 图2.2账单信息添加函数流程图2. 在对账单信息进行排序的过程中,采用的方
4、法是:首先将账单中支出最大和最小的两个结点寻找出来并按从小到大的顺序连接到一个新申请的头结点上;再将原函数的各结点插入到新的链表中,最终新的链表就成为了排序后的新账单。paixu()函数流程图如图2.3所示。图2.3 排序函数流程图3. 进入账单信息查询部分,程序根据输入的日期进行逐一比较,若存在该日期的账单信息,程序输出相应的账单信息,若不存在该日期的账单信息,系统提示用户还未录入该日期的账单信息。账单查询函数流程图如图2.4所示。 图2.4 查询函数流程图4. 进入账单更改部分,程序将用户输入的需更改的账单日期与已存在的账单日期进行逐步比对,对日期完全相同的账单信息进行更改,若不存在该日期
5、的账单信息,程序提示用户是否马上进行添加。流程图如图2.5所示。 图2.5 账单信息更改流程图5. 进入账单保存部分,用户对建立的账单以文本文档的形式保存到磁盘中,账单信息保存函数流程图如图2.6所示。 图2.6 保存账单信息函数流程图3 数据结构分析3.1 存储结构主要存储结构:带头结点的单向链表存储结构。typedef struct MYBILL /链表结点结构long date; /日期信息long food; /食品消费long fangzu; /房租费用 long jiaoyu; /子女教育费long shuidian; /水电费 long yiliao; /医疗费 long chu
6、xu; /储蓄long pay; /总支出long income; /总收入struct MYBILL*next; /指向下一结点的指针MYBILL,bill;3.2 算法描述1. 建立单向链表,用来存储账单信息:首先分别输入将要建立账单的年份及月份,年份的合理范围定为所有正整数,当年份输入为非合理数字时结束对账单的录入;月份的合理范围为1至12,当输入不属于该范围的月份数据时,程序会重新进行年份和月份的录入;录入日期数据后,进行其余信息的录入。void *tianjia(MYBILL *head) /向原链表添加新的链表结点int i,j; /定义年份和月份变量MYBILL *p,*tail
7、; /定义结构体类型指针p=head; /将指针p初始化为headwhile(p-next!=NULL) /判断账单链表是否为仅含空头结点的链表p=p-next; /将指针p向后移动一个单位printf(nt输入您要建立账单的年份,当输入非正数时结束输入!nt);scanf(%ld,&i); /输入年份数据while(i0) /判断输入的年份是否为合理数据printf(nt输入您要建立账单的月份nt);scanf(%d,&j); /输入月份数据if(j0&jdate=100*i+j; /将年份和月份为转为一长整数字存储tail-next=NULL; /新结点的指针域指向空printf(nt输入
8、 食品费用:t);scanf(%ld,&tail-food); /输入食品费用printf(nt输入 房租:t);scanf(%ld,&tail-fangzu); /输入房租费用printf(nt输入 子女教育费:);scanf(%ld,&tail-jiaoyu); / 输入子女教育费printf(nt输入 水电费:t); scanf(%ld,&tail-shuidian); /输入水电费printf(nt输入 医疗费:t);scanf(%ld,&tail-yiliao); /输入医疗费printf(nt输入 储蓄:t);scanf(%ld,&tail-chuxu); /输入存储printf(
9、nt输入 总收入:t);scanf(%ld,&tail-income); /输入总收入tail-pay=tail-food+tail-fangzu+tail-jiaoyu+tail-shuidian+tail-yiliao;/将所有支出相加作为总支出p-next=tail; /将新申请的结点链接到原链表的最尾端p=p-next; /指针p向后移动一个单位elseprintf(nt输入月份不合理,请重新输入!nt);printf(nt输入您要建立账单的年份,当输入非正数时结束输入!nt);scanf(%ld,&i); /输入年份信息MYBILL *jianli(MYBILL *head) /建立
10、账单链表函数MYBILL *head; /定义结构体类型指针tianjia(head); /调用子函数tianjia()if (head-next!=NULL) /判断账单链表是否为仅含空头结点的链表printf(nttt=账单录入成功!=nn);elseprintf(nttt=没有账单录入!=nn);return head; /返回头指针 2. 账单排序,排序方法采用将所有数据中最小和最大值挑选出来,再将处于这两个数据中间位置的其他数据进行插入。MYBILL *paixu(MYBILL *head) /账单信息排序函数long min,max; /定义两个变量对两个最值数据进行标记int i
11、,j; /年份月份定义MYBILL *q,*t,*p,*head1; /定义结构体类型指针q=head-next; /将q初始化为head-nextif(head-next!=NULL) /判断链表是否为只含头结点的空链表min=q-pay; /第一结链表支出最少t=head; /初始化指针t的值p=q; /初始化p的值while (q-next!=NULL) /月支出最小结点为新排序账单的第一个结点if (minq-next-pay) /比较q的pay和q-next的pay大小min=q-next-pay; /如果p-next的pay小将其值赋给minp=q-next; /用p标记支出最少的
12、结点t=q; /用t标记支出最少的结点的上一结点 以便摘除支出最少的结点q=q-next; /将指针q向后移动一个单位t-next=p-next; /将支出最少的结点摘下head1=(bill *)malloc(sizeof(bill); /申请排序后链表头结点head1-next=p; /将最小支出连接到新链表后作为第一个结点p-next=NULL; /将新链表尾端指向空q=head-next; /再次将q指向原链表头指针的后一结点if(q!=NULL) /判断链表是否为只含头结点的空链表max=q-pay; /月支出最大结点为新排序账单的第二个结点t=head; /初始化指针t的值p=q;
13、 /初始化p的值while (q-next!=NULL) /判断是否只存在最大最小支出外if (maxnext-pay)/比较max与q-next-pay的大小max=q-next-pay;/如果p-next的pay小将其值赋给maxp=q-next; /用指针p标记支出最多的结点t=q; /用指针t标记支出最大的结点 以便摘除支出最多的结点q=q-next;/将指针q向后移动一个单位长度t-next=p-next; /摘掉支出最大的结点head1-next-next=p; /将最大支出连接到新链表后p-next=NULL; /将新链表尾指向空 q=head-next; /第三次初始化指针qw
14、hile (q!=NULL) /依次从原表中摘取结点插入到新表,使其有序 head-next=q-next; /将q结点摘除p=head1-next; /初始化p指向新链表头结点的下一结点while (q-payp-next-pay)/比较原链表与新链表支出p=p-next; /将新链表的p结点向后移动 q-next=p-next;/将q结点链接到p后p-next=q;q=head-next;/将q重新置于head后结点上head=head1; /将新链表头指针赋给原链表头指针p=head-next; /初始化pwhile (p!=NULL) /输出排序后的结果i=p-date/100;j=p
15、-date%100;printf(ntt日期:%d年%d月ntt食品费用:%ldnt房租:%ldntt子女教育费:%ldntt水电费:%ldntt医疗费:%ldntt储蓄:%ldntt总支:%ldntt收入:%ldn,i,j,p-food,p-fangzu,p-jiaoyu,p-shuidian,p-yiliao,p-chuxu,p-pay,p-income);p=p-next;elseprintf(nt您还未建立账单,无法执行排序及查看操作!n);return head;3.输入将要查询的日期,程序将输入的数据转化与账单信息比较,将符合的账单信息输出。void chaxun(MYBILL *
16、head) /查询单月账单函数long k;int i,j,m=0;MYBILL *p;if(head-next!=NULL) /判断账单是否为空账单printf(nt输入0退出查询,请输入您要查询的年份:);scanf(%d,&i); /输入查询的年份while(i0) /判断输入年份为合理数据m=0; /使用m标记查询的日期是否存在p=head-next; printf(nt请输入您要查询的月份:);scanf(%d,&j); /输入查询的月份if (j0&jdate) /判断是否存在输入的日期信息 m+; /变化m值,以表示存在记录printf(ntt日期:%d年%d月ntt食品费用 :
17、%ldntt房租:%ldntt子女教育费:%ldntt水电费:%ldntt医疗费 :%ldntt储蓄:%ldntt总支出:%ldntt收入:%ldn,i,j,p-food,p-fangzu,p-jiaoyu,p-shuidian,p-yiliao,p-chuxu,p-pay,p-income);break;p=p-next;if(m=0) /依据m值判断是否查询成功printf(nt您查询的日期无记录!n);elseprintf(nnt您输入的月份不合理!n);printf(nt输入0退出查询,请输入您要查询的年份:);scanf(%ld,&i);elseprintf(nt您还没建立账单!n)
18、;4.输入需更改的账单日期,进行更改,若不存在记录,程序设有添加功能。 MYBILL *genggai(MYBILL *head) /更改账单函数long i,j,k;int m,s;MYBILL *p;p=head-next;printf(nt输入0退出更改,请输入您要更改的年份:);scanf(%ld,&i); /输入更改账单的年份while(i0) /判断年份合理与否m=0; /使用m标记是否存在该日期账单记录printf(nt请输入您要更改的月份:);scanf(%ld,&j); /输入更改账单的if (j0&jdate)printf(nt输入 食品费用:t); /输入更改后的账单信息
19、scanf(%ld,&p-food);printf(nt输入 房租:t);scanf(%ld,&p-fangzu);printf(nt输入 子女教育费:);scanf(%ld,&p-jiaoyu);printf(nt输入 水电费:t);scanf(%ld,&p-shuidian);printf(nt输入 医疗费:t);scanf(%ld,&p-yiliao);printf(nt输入 储蓄:t);scanf(%ld,&p-chuxu);printf(nt输入 总收入:t);scanf(%ld,&p-income);p-pay=p-food+p-fangzu+p-jiaoyu+p-shuidian
20、+p-yiliao;m+; /改变m值,标记已更改账单信息break;p=p-next;if(m=0) /判断是否更改成功printf(nt您要更改的日期无记录!是否立即添加?(1-是,其余键-否) );scanf(%d,&s); /输入提示的操作,选择是否添加账单信息if (s=1)tianjia(head); /调用子函数技进行账单信息添加else printf(nnt您输入的月份不合理!n);printf(nt输入0退出更改,请输入您要更改的年份:);scanf(%ld,&i);return head;6. 以文本文档形式保存账单信息,保存路径为程序所在位置。void xieru(MYB
21、ILL *head)FILE * fp;MYBILL *p;p=head-next;char ch,filename10;if(head-next!=NULL)printf(nt输入将要保存的文件名:); scanf(%s,filename); /输入保存的文件名if (fp=fopen(filename,w)=NULL)printf(n不能打开!n);exit(0);ch=getchar(); /接受文件名输入后的回车符while (p!=NULL) /判断账单是否为空fprintf(fp,日期:%ld,食品费用:%ld ,房租:%d,子女教育费:%ld,水电费:%ld,医疗费:%ld,储蓄
22、:%ld,总收入:%ld,p-date,p-food,p-fangzu,p-jiaoyu,p-shuidian,p-yiliao,p-chuxu,p-income);p=p-next;fclose(fp); /关闭文件elseprintf(nt您未建立新账单,无法保存!n);4.1 调试过程在调试程序是主要遇到的问题是:在程序最开始运行时,如果还没有建立账单信息,则此时查询、查看、更改和保存时由于没有头指针传入子函数,程序会出现错误而停止运行。解决方法:采用使用带有头结点的链表存储账单信息,在程序运行时即刻申请头结点,在进入子函数后,对头结点后是否为空进行判断来判断是否已经录入账单信息,从而避
23、免了问题的再次发生。4.2程序执行过程运行程序,运行结果如下图输入1,选择账单录入功能,结果如下图输入账单的日期为2012年1月,分别输入各项开支,如下图录入账单完成后,选择查询功能,如下图输入查询日期2012年1月,运行结果如下图返回主菜单后,选择账单存储,如下图输入保存的文本文件名为201201,如下图文本文件保存结果如下图参考文献1 严蔚敏,吴伟民.数据结构M.北京:清华大学出版社,2007.2 张长海,陈娟.C程序设计M.北京:高等教育出版社,2004. 3 谭浩强.C程序设计M .北京:清华大学出版社,2005.4 朱国进。程序设计与问题求解.北京:东华大学出版社,2004.5陈国良
24、。.并行计算结构算法.北京:高等教育出版社,1999 6石峰。. 程序设计基础. 北京:清华大学出版社,20037郝玉洁等. C语言程序设计. 北京:机械工业出版社,2000 8高克宁等。.C语言程序设计.北京:科学出版社,2003 课程设计总结:通过这次课程设计,使我对数据结构有了更加深入的认识,尤其在链表的建立和使用方面又有了显著的巩固和提高,同时巩固了大一年学习的知识,尽管在设计过程中遇到了一些困难,但通过查阅资料、请教老师、请教学长和同学的方法,把一个又一个问题解决,成功地完成了课设题目。这次课程设计练习了我的动手能力,让我意识到平时的上机练习是多么的重要,同时,我更加的相信,只要努力就一定会有收获,只有掌握扎实的知识,获得成功才会更加容易,因此,在进后的学习中我会加倍努力,从而令我的编程努力得到更大的提升,让我编出的程序更加的完美。指导教师评语:指导教师(签字): 年 月 日课程设计成绩