通讯录的设计数据结构课程设计含代码.docx
《通讯录的设计数据结构课程设计含代码.docx》由会员分享,可在线阅读,更多相关《通讯录的设计数据结构课程设计含代码.docx(27页珍藏版)》请在冰点文库上搜索。
通讯录的设计数据结构课程设计含代码
课程设计说明书
课程名称:
数据结构课程设计
专业:
电子信息科学与技术班级:
2012-1
设计人:
山东科技大学
2015年7月11日
山东科技大学
课程设计任务书
一、课程设计题目:
通讯录的设计
二、设计原始资料:
CodeBlocks软件、双链表数据结构、C语言参考书
三、设计应解决下列各主要问题:
1、提供输入信息的接口,使用户能增加联系人
2、能够删除联系人
3、能够显示所有联系人
4、能够以姓名为关键字查找联系人
5、能够把通讯录信息保存的文件内,并在下次运行软件时载入供用户查看和操作
四、设计说明书应附有下列图纸:
五、小组分工说明:
:
程序总体架构,增加联系人模块,删除联系人模块,将联系人信息存盘,从文件中读取联系人信息模块;
:
基本数据结构构造,命令判断模块,显示联系人模块,查找联系人模块。
六、命题发出日期:
2015年7月4号 设计完成日期:
2015年7月11
指导教师评语
成绩:
指导教师(签章):
年 月 日
1需求分析说明…………………………………………………………1
2概要设计说明…………………………………………………………1
2.1数据结构定义……………………………………………………1
2.2整体程序流程图………………………………………………………2
3详细设计说明…………………………………………………………3
3.1主函数模块………………………………………………………3
3.2增加联系人模块………………………………………………………3
3.3删除联系人模快………………………………………………………3
3.4查找联系人模块………………………………………………………4
3.5联系人保存到文件模块………………………………………………5
3.6读取文件中的联系人信息模块………………………………………6
3.7命令接收与判断模块…………………………………………………8
3.8显示联系人信息模块…………………………………………………8
4调试分析…………………………………………………………8
4.1遇到的问题……………………………………………………8
4.2调试……………………………………………………………8
5用户使用说明………………………………………………………11
6课程设计总结……………………………………………………12
1需求分析说明
通讯录管理系统总体设计目标:
用《数据结构》中的双向链表作数据结构,结合C语言基本知识,编写一个具有良好可操作性、有一定容错能力通讯录管理系统,以把所学数据结构知识应用到实际软件开发中去。
其中联系人的信息包括姓名、街道、城市、邮编、国家等几项。
系统在命令行模式下运行,通过输入命令的方式操作。
根据以上基本要求分析出系统应具备以下功能:
显示所有联系人信息,向通讯录中添加新的联系人,删除指定联系人,将联系人信息保存到文件中,从文件中读取联系人信息到内存,以姓名为关键字查找联系人。
根据以上要实现的功能,首先要构造一个保存联系人信息的数据结构person_info,根据要求这个结构应具有两个指针域以指向其前一个结构和后一个结构从而构成双链表;其数据域包括姓名、街道、城市、邮编、国家等信息,这些信息分别保存在字符数组中。
除了基本的联系人结构(相当于双链表的一个结点)还应构造一个person_list结构,包括一个指向第一个联系人结点的指针和一个保存链表长度的元素。
2概要设计说明
2.1数据结构定义
考虑到本系统在初始化阶段要进行大规模的插入操作以构造链表,故采用插入元素较为方便快速的链式存储结构。
而在查看联系人信息时需要查看下一个和上一个联系人,故采用双向链表存储结构。
为了更方便的操作,再构建一个“链表”结构,其指针域指向第一个结点,数据域保存链表的长度。
//定义链表结点(联系人)结构体
typedefstructperson_info{
charname[NAME_LENGTH+1];//姓名
charstreet[STREET_LENGTH+1];//街道
charcity[CITY_LENGTH+1];//城市
chareip[EIP_LENGTH+1];//邮编
charstate[STATE_LENGTH+1];//国家
structperson_info*next_person;//指向下一个结点
structperson_info*prior_person;//指向前一个结点
}person_info,*position;
//定义链表结构
typedefstruct{
person_info*head;//指向第一个结点(第一个联系人)
intlen;//链表长度
}person_list;
2.2整体程序流程图
根据需求分析,本程序的主体框架采用命令驱动的模式,即不断进行接收命令、执行命令的循环,直到接收的退出命令。
程序首先执行的读取文件中的联系人信息以此为基础建立联系人链表,然后显示主界面即命令菜单和用户交互。
在程序运行期间,命令菜单一直保持在界面上部,有利于系统使用的方便性。
系统一共有增加联系人、删除联系人、查找联系人、联系人信息保存到文件、读取文件中的联系人信息、命令接收与判断、显示所有联系人等七个主要模块。
图2.1整体程序框图
3详细设计说明
3.1主函数模块
首先调用读取文件中的联系人信息模块,建立本次运行所需链表。
然后显示住菜单。
接着进人接收命令、执行命令的死循环,直到得到退出命令退出程序。
3.2增加联系人模块
引导用户输入联系人姓名、街道、城市、邮编、国家等信息,将联系人信息保存到新构造的结点中,最后将结点插入到链表中。
图3.1增加联系人信息模块框图
3.3删除联系人模块
删除联系人模块提供了友好的用户交互界面,用户通过命令一个一个地查看联系人信息,当查找到自己想删除的联系人时输入删除命令删除;也可以直接搜索出联系人来删除。
图3.2删除联系人模块
3.4查找联系人模块
查找联系人模块,通过用户输入联系人姓名查找出对应的联系人信息;值得一提的是这里的搜索和删除模块中的搜索采用了同样的底层函数。
图3.3查找联系人模块框图
3.5联系人保存到文件模块
此模块用到了C语言的文件操作相关库函数fopen(),fwrite(),fclose()等函数;其中fopen()函数打开要保存信息的文件,fwrite()以一个结点为单位向文件中写入信息,最后用fclose()函数关闭文件。
图3.4联系人保存到文件模块
3.6读取文件中的联系人信息模块
此模块用到了C语言的文件操作相关库函数fopen(),fread(),fclose()等函数;其中fopen()函数打开要保存信息的文件,fread()以一个结点为单位从文件中读取联系人信息,最后用fclose()函数关闭文件
3.7命令接收与判断模块
设定的所有命令都为单个字符,考虑到用户可能一次输入多个字符所以用字符数组保存用户的输入,真正当做命令的是该数组的第一个非空字符。
3.8显示联系人模块
此模块较为简单,只是从头到尾遍历一遍整个链表。
4调试分析
4.1遇到的问题:
在一些函数中需要改变指针变量本身的值(不是指针指向的变量的值),在《数据结构》课本中采用的C++语言中才有的引用特性解决的这一问题。
由于本系统完全采用C语言编写,故不能采用上述解决方案,只能采用指向指针的指针的方式。
指针用起来感觉总有些危险,只能加倍小心避免各种陷阱。
现在系统只经过初步的测试,仍有可能存在潜在的Bug。
4.2调试
在CodeBlocksIDE开发环境下编写代码,选择Debug模式,编译运行程序。
增加联系人模块:
根据菜单输入命令A或a,然后根据提示输入联系人姓名、街道、城市、邮编、国家等信息。
重复执行此步骤,加入了十多个联系人。
显示联系人模块测试:
输入命令l或L,得到所有联系人信息列表。
删除联系人模块测试:
进入删除界面,选择要删除的联系人,输入命令d或D删除联系人。
删除后返回主界面,再次列出联系人信息(l或L)发现刚才删除的联系人已经不再列表中了。
查找模块测试:
在主界面输入f命令,进行搜索。
下图显示了搜索失败和成功两种情况。
存盘模块测试:
在主界面输入s命令,将本次运行程序对通讯录的修改保存到记录文件中。
然后输入q命令退出程序。
或者直接输入q退出,根据提示选择保存信息。
接着再次运行程序,输入l命令查看上次程序运行保存的信息是否正确读入。
5用户使用说明
本系统运行在命令提示符模式下,所有操作都通过键盘输入命令进行。
运行系统后,首先显示的是主菜单。
根据提示可以选择添加联系人、显示联系人、查找联系人、删除联系人、存盘、清屏和退出等操作。
其中,删除联系人操作是在另一个界面下进行的,在该界面可以输入命令查看下一个、上一个和删除当前显示的联系人操作,也可以直接输入f命令搜索出联系人后删除。
最后可以输入命令b返回到主界面。
在主界面输入f命令进行搜索联系人操作,根据输入的联系人姓名,系统将查找出相应的联系人若该联系人不存在则输出提示信息。
输入l命令,启动显示功能,系统列出所有已知联系人的信息供用户查看。
在添加或删除联系人后可以输入s命令将修改后联系人列表保存到文件。
如果,执行添加或删除操作后没有保存则在退出系统时询问用户是否保存。
当界面信息过多时,可以输入c命令清屏,并且不影响菜单显示。
最后,输入q命令退出系统。
6课程设计总结
本次课程设计,使用到了数据结构课程中学习到的双链表的相关知识,用到了链表的插入、删除和遍历等操作。
通过用具体的语言实现一个完整的数据结构加深了对链表的理解和掌握。
除了对数据结构知识的实践,本次设计还用到了很多C语言中的知识,正如4.1节所言,在使用一些不大熟悉的C语言主题时暴露了很多问题的同时也加强了对C语言的认识。
本次课程设计是和**同学一起完成的。
在设计初期,我们首先讨论的是系统最后的表现形式。
我们提出了两种方案,一是在命令提示符窗口通过输入命令进行操作的方式(即通常所说的小黑框);二是提供在Windows下的图形界面,利用鼠标和键盘操作。
考虑到我们都没有Windows图形界面编程经验且课程设计时间较短,于是我们选择了第一种方案。
即使是易于实现的第一种方案也是有较大的工作量的。
按照模块化编程的思想,我们把系统划分为主要的7个模块,我负责其中的4个模块,康杨同学负责另外的3个模块。
这次设计的通讯录系统运行较为稳定在测试中没有崩溃的情况,使用也较为方便,给一些同学试用后反应良好。
但我们知道系统肯定还存在潜在的Bug等待我们发现。
我们会持续维护这个系统,继续添加功能,使其越来越稳定和易于使用。
参考文献:
1.《数据结构C语言版》严蔚敏清华大学出版社
2.《C语言程序设计现代方法》K.N.King人民邮电出版社
附录:
程序代码
注:
下面包含3个文件,如果要运行,应分别保存为3个文件即type.h、type.c和main.c。
其中main.c是主文件,即main函数所在的文件。
下面的程序都是可以运行的。
上文中的截图也是真实的。
如果还不知道怎么运行可以在XX上私信我,我教你。
共包含3个文件:
type.h:
数据结构定义(第13页开始)
type.c双链表基本操作构造链表删除结点插入结点等(第13页开始)
main.c主文件包含大部分逻辑(第17页开始)
/*****************************************************************
*type.h数据结构定义
*****************************************************************/
typedefstructperson_info{
charname[NAME_LENGTH+1];
charstreet[STREET_LENGTH+1];
charcity[CITY_LENGTH+1];
chareip[EIP_LENGTH+1];//Óʱà
charstate[STATE_LENGTH+1];
structperson_info*next_person;
structperson_info*prior_person;
}person_info,*position;
typedefstruct{
person_info*head;//指向第一个结点
intlen;
}person_list;
/*****************************************************************
*type.c数据结构基本操作
*****************************************************************/
#include"type.h"
#include"stdlib.h"
/******************************************************************
*函数名:
InitPersonList()
*功能:
构造空表
*输入:
person_list指针
*输出:
保留
******************************************************************/
StateInitPersonList(person_list*p)
{
p->head=NULL;
p->len=0;
returnOK;
}
/*****************************************************************
*函数名:
DestroyPersonList()
*功能:
销毁链表中的节点
*输入:
表指针
*输出:
保留
******************************************************************/
StateDestroyPersonList(person_list*p)
{
person_info*q;
person_info*m;
q=p->head;
while(q!
=NULL)
{
m=q->next_person;
free(q);
q=m;
}
p->head=NULL;
p->len=0;
returnOK;
}
/******************************************************************
*函数名:
InsFrist
*功能:
将结点this_person插入到头结点head之后
*这里要改变指针的值,所以用了指向指针的指针
*输入:
头结点,要插入的结点
*输出:
保留
******************************************************************/
StateInsFrist(position*head,person_info*this_person)
{
//if(this_person==NULL||head==NULL)
//returnERROR;
if((*head)==NULL)
{
(*head)=this_person;
(*head)->next_person=NULL;
(*head)->prior_person=(*head);
}
else
{
//将新节点插入到头结点之后
this_person->next_person=(*head)->next_person;
this_person->prior_person=(*head);
if((*head)->next_person!
=NULL)
(*head)->next_person->prior_person=this_person;
else
(*head)->prior_person=this_person;
(*head)->next_person=this_person;
}
//p->len++;
returnOK;
}
/******************************************************************
*函数名:
DelPerson()
*功能:
已知头结点head,删除结点p。
考虑到了,只有一个结点、删除最
*后一个结点、删除头结点等情况
*输入:
头结点,要删除的结点。
其中因为可能改变头结点的值,所以用了
*指向指针的指针
*输出:
保留
******************************************************************/
StateDelPerson(position*head,person_info*p)
{
if(p==NULL||(*head)==NULL)
returnERROR;
if(p==(*head))//头结点,包括只含一个结点的情况
{
(*head)=p->next_person;
if(p->next_person!
=NULL)
p->next_person->prior_person=p->prior_person;
}
elseif(p->next_person==NULL)//最后一个结点,至少一共两个结点
{
(*head)->prior_person=p->prior_person;
p->prior_person->next_person=p->next_person;
}
else//其它情况
{
p->prior_person->next_person=p->next_person;
p->next_person->prior_person=p->prior_person;
}
free(p);
returnOK;
}
/*****************************************************************
*main.c主文件
*****************************************************************/
//记录文件
#defineRECORE_FILE"record.dat"
//全局变量
intneed_save=0;//标志变量非0:
:
修改通讯录后没有保存
/******************************************************************
*函数名:
main()
*功能:
主函数
*输入:
无
*输出:
0
******************************************************************/
intmain()
{
intcmd;
person_listp_list;
InitPersonList(&p_list);
disply_screen(MAIN_SCREEN);
load_records(&p_list);//载入记录
cmd=get_command();
while(cmd!
=QUIT)//deadloop接受命令->执行命令
{
switch(cmd){
caseADD:
add_person(&p_list);
break;
caseLIST:
list_person(p_list);
break;
caseCLEAR:
system("cls");
disply_screen(MAIN_SCREEN);
break;
caseDELETE:
delete_person(&p_list);
break;
caseSAVE:
save_2_file(p_list);
need_save=0;//清除“需要保存”标志
break;
caseFIND:
find_in_record(p_list);
break;
default:
break;
}
cmd=get_command();
}
if(need_save!
=0)//修改(增加,删除)后没保存
{
printf("是否保存修改?
(Y/N)\n");
cmd=get_command();
if(cmd==YES)
save_2_file(p_list);
}
DestroyPersonList(&p_list);
return0;
}
/******************************************************************
*函数名:
get_command()
*功能:
得到用户的输入的正确命令
*输入:
无
*输出:
用户命令
******************************************************************