c++设计简单的数据库管理文档格式.docx
《c++设计简单的数据库管理文档格式.docx》由会员分享,可在线阅读,更多相关《c++设计简单的数据库管理文档格式.docx(19页珍藏版)》请在冰豆网上搜索。
本题目要求应用MFC对话框编程技术,完成一个可视化的通讯录编程。
相比于以往的单文件编程而言,这个题目则要求建立一个工程文件,对这个工程要进行联合编程和编译连接。
本题目编程过程中,首先要制作一个对话框界面,添加各按钮。
然后定义一个AddressBookList.h的头文件,完成节点类和通讯录类的定义,并建立双向链表。
最后完成相应按钮消息映射函数程序的编写。
2.2总体设计框架:
2.3功能模块:
从功能上说,该系统可以划分为两大功能模块,即用户操作界面模块(人机交互模块)和数据(通讯录)管理模块。
2.3.1数据管理模块:
把通讯录信息放到一个双向循环链表中管理。
根据系统要求,应该实现的链表操作函数为:
初始化链表、销毁链表,链表插入操作、链表删除操作、定位元素在链表中的位置、修改链表中某个结点的数据、遍历链表、移动指针等。
2.3.2人机交互模块:
⑴新建:
新建一个空白页,以便输入信息。
⑵添加:
将当前名片按姓名顺序添加到通讯录中,不能重复添加通讯录中已存在的名片。
⑶删除:
删除当前名片。
⑷修改:
在当前页面上修改信息后点击该按钮,可修改通讯录中的信息。
姓名字段为关键字,不能修改
⑸第一页:
显示第一页名片信息
⑹上一页:
显示上一页名片信息
⑺下一页:
显示下一页名片信息
⑻最后页:
显示最后页名片信息
⑼查找:
以姓名为关键字,查询并显示该名片信息
⑽载入:
读取“addlist.txt”文件中的通讯录信息。
本题目中设置为自动载入,无需按钮。
⑾保存:
将通讯录保存到“addlist.txt”文件中。
⑿退出:
退出通讯录系统程序,关闭对话框。
三、详细设计:
3.1数据管理模块:
数据结构包括:
个人信息结构体Person、节点类Node和双向循环链表类Book。
基本操作包括:
NewNode:
建立新节点
Book:
建立一个空的双向循环链表。
~Book:
销毁链表:
清空链表并销毁表头结点。
Isempty:
判断链表是否为空。
FirstNode:
将当前记录指针移到链表第一个数据节点。
LastNode:
将当前记录指针移到链表尾节点。
PreNode:
将当前记录指针向前移动一个节点,若已经为第一个数据节点,则不移动。
NextNode:
将当前记录指针向后移动一个节点,若已经为尾节点,则不移动。
Add:
将新节点按姓名顺序添加到链表中。
TF
F遍历链表查找插入点
T
T
F
F
T插在中间
情况1:
p2在尾部且p2姓名比p大;
情况2:
p2不在尾部且p2姓名比p大;
情况3:
p2不在尾部但与p重名
TF
(p2姓名比p大)
SearchNode:
以姓名为关键字,查找包含该姓名的节点在链表中的位置。
TF
FT
Delete:
删除当前节点。
Load:
将文件中的数据读取到链表中。
Save:
将链表中的数据保存到文件里。
3.2人机交互界面模块:
用户操作模块完成计算机和用户的信息交互,要求操作界面友好。
根据这一原则和系统功能要求设计界面如下:
制作对话框,添加控件:
1新建:
删除当前节点,显示删除后的链表的当前节点信息
在当前页面上修改信息后点击该按钮,若未修改姓名,将修改后的信息复制给当前节点,提示“修改成功”。
若姓名被修改,提示“姓名不能修改”,显示修改前信息。
将当前记录指针移动到第一个数据节点,显示该节点的信息。
若链表为空,显示为空白页。
将当前记录指针移动到上一个数据节点,显示该节点的信息
显示该节点的信息
将当前记录指针移动到链表尾节点,显示该节点的信息
⑼查找:
退出前自动执行析构函数,销毁链表。
四、编码部分
4.1数据管理模块AddressBookList.h
structPerson//个人信息类
{
charName[15];
//姓名
charPhone[15];
//电话
charEmail[30];
//邮箱
charQQ[15];
//QQ号
charAddress[30];
//地址
};
classNode//节点类
public:
friendclassBook;
//Book为Node的友元
Node(Personitem){data=item;
pre=NULL;
next=NULL;
}//构造函数
Persondata;
//结点的数据元素域
private:
Node*pre;
//节点的指针域
Node*next;
classBook//双向链表类
protected:
Node*head;
//首节点指针
Node*tail;
//尾指针
Node*currentp;
//当前节点指针
intcurrent;
//当前记录号
inttotal;
//总记录号
Node*NewNode();
//建立一个新节点,将其中数据全部清空
Book();
//构造函数,建立一个空的双向链表
~Book();
//析构函数,从第一个数据节点开始循链删除节点,直到指针移到表头结点;
然后删除表头结点;
intIsempty();
//判断是否为空链表,返回值为1说明空
voidFirstNode();
//将当前记录指针移到链表第一个数据节点,若链表为空,移动到头结点
voidLastNode();
将当前记录指针移到链表尾节点,当前页码置为总页码;
若为空链表,将当前结点指针置为头结点,当前页码归零
voidPreNode();
//将当前记录指针向前移动一个节点,若已经为第一个数据节点,则不移动
voidNextNode();
//将当前记录指针向后移动一个节点,若已经为尾节点,则不移动
intSearchNode(char*name);
//以姓名为关键字,查找该记录
voidAdd(Personitem);
//按姓名顺序添加数据项
voidDelete();
//删除当前结点
voidSave();
//将链表中的数据保存到文件里.遍历链表,输出节点数据,节点信息的每一项间隔一个水平制表符
voidLoad();
//将文件中的数据读取到链表中
intBook:
:
Isempty()//判断是否为空链表,返回值为1说明空
if(head->
next==head)return1;
elsereturn0;
}
SearchNode(char*name)//以姓名为关键字,查找该记录。
n=0:
没有要查找的记录;
n=1:
查找成功;
n=2:
已经是最后一条同名记录
Node*p=head->
next;
//定义节点指针p指向第一个数据节点
intn=0;
intc=current;
//保存当前记录号
if(strcmp(currentp->
data.Name,name)==0)//检查当前节点姓名是否为待查姓名,若相同,检查下一个;
若不同,从头检查
{
if(strcmp(currentp->
next->
data.Name,name)==0)//若下一个相同,将当前指针移到下一个;
不同则不移动
{currentp=currentp->
current++;
n=1;
elsen=2;
}
else
current=0;
//当前记录号置为零
for(;
p!
=head;
=p->
next)//循环一周
current++;
//循环一次当前记录号加一
if(strcmp(p->
data.Name,name)==0)//比较p指向节点的姓名与要查找的姓名是否相等。
若相等,当前节点指针移至p节点
{
currentp=p;
n=1;
break;
}
if(n==0)
current=c;
//若未查找到,当前记录变为原记录,当前节点指针不移动
returnn;
voidBook:
Add(Personitem)//按姓名序添加记录,然后第1个记录变成当前记录
Node*p,*p1,*p2;
//p为要插入的节点指针
p=newNode(item);
p2=p1=head->
if(Isempty())//若为空链表
{插入该记录;
修改尾指针;
使current++;
elseif(strcmp(p2->
data.Name,p->
data.Name)>
0)
插在链表首部;
current=1;
else//插在链表中间或尾部
while(p2!
=tail&
&
(strcmp(p2->
data.Name)<
0))//查找待插入点
p1=p2;
//p1,p2同步移动
p2=p2->
//p2移到下一个结点
current++;
//当前页码加一
}
if(p2==tail&
strcmp(p2->
=0)//若p2已移动到链表尾部且p2姓名小于或等于p,将p插到尾部
修改表尾指针;
else//插在中间(情况1:
p2不在尾部但与p重名)
if(strcmp(p2->
data.Name)==0)//若p2不在尾部但与p重名,将p插到p2后面(此时p1=p2)
{
current++;
p1=p2;
}
将p插在p1后面;
currentp=p;
total++;
//总记录号加1
Delete()//删除当前节点
Node*p=currentp;
Node*pl=currentp->
pre;
if(链表不空)
pl->
next=p->
//重新拉链
p->
pre=pl;
if(currentp==tail)//删除的是尾节点
tail=pl;
//修改尾指针
tail->
next=head;
head->
currentp=tail;
current--;
elsecurrentp=currentp->
deletep;
total--;
//删除后总记录数减一
if(total==0)
currentp=head;
current=0;
}
Load()//将文件中的数据读取到链表中
while(fin.good())
{
建立新节点p2
将字符串读取到p2结点的数据项里,遇'
\t'
终止
fin.getline(p2->
data.Name,15,'
);
……
将p2结点插入到链表尾部,修改尾指针
currentp=head->
//将当前记录指针移到第一个数据节点
4.2人机交互模块:
AddressBookDlg.cpp
Booklist;
//全局变量,界面上所有操作均对此对象进行
按钮消息映射函数如下
BOOLCAddressBookDlg:
OnInitDialog()//初始化
调用Load函数,载入文件中的数据;
显示第一页
voidCAddressBookDlg:
OnFirstPage()//显示第一页
调用FirstNode函数,移至第一个数据节点,显示该节点信息;
OnPrePage()//上一页
调用PreNode函数,移至上一个结点,显示该节点信息
OnNextPage()//下一页
调用NextNode函数,移至下一个结点显示该节点信息
OnLastPage()//最后页
调用LastNode函数,移至链表尾节点显示该节点信息;
OnXinjian()//将页面信息清空以便添加新名片
OnAdd()//添加名片
If(编辑框的内存变量的信息与当前节点的信息完全相同)
MessageBox("
已存在相同记录"
调用Add函数,将编辑框的内存变量的信息添加到链表中;
OnDelete()//删除当前名片
调用Delete函数,删除当前节点,显示删除后的链表的当前节点的信息
OnFind()//查找
调用SearchNode函数,返回值赋给变量find;
find=1时:
显示当前节点信息;
查找成功"
);
find=2时:
最后一条同名记录"
find=0时:
MessageBox("
没有要查找的记录"
OnEdit()//修改
if(姓名未被修改)
{MessageBox("
修改成功"
修改链表中的数据;
姓名不能修改!
"
)显示修改前的当前节点信息;
OnSave()//调用Save函数,将链表中的信息保存到文件中
OnExit()//退出程序,关闭对话框
五、系统使用说明:
各按钮作用如下:
清空页面,以便输入信息。
六、总结:
6.1需要继续完善之处:
1.新建:
可改为打开一个新的对话框。
2.查找:
可改为能实现对所有关键字的查找
3.载入:
可改为输入文件名称后打开该指定文件
4.页面显示:
可改为用列表框同时显示多人信息
5.排序:
可增加对各类关键字的排序功能
6.2疑难问题的处理:
1.问题:
点击添加按钮会将已存在的名片添加到链表中
解决方法:
在“添加”按钮消息映射函数中,先检查编辑框的内存变量中的数据在链表中是否已有完全相同的记录。
若有,拒绝添加该名片
2.问题:
删除最后一张名片时系统会报错。
正确编写删除操作中各节点间指针的移动顺序和指向,将头结点的数据设定为空,删除最后一个数据节点后,将当前记录指针移到头结点上。
3.问题:
在链表中间插入重名记录时,当前页码数比正确数据少一
若p2不在尾部但与p重名,将p插到p2后面时,使当前页码数current++;
4.问题:
在链表尾部插入记录时,该记录被添加到了倒数第二位。
如想在张晟后面添加周政,结果通讯录中周政出现在张晟前面
原因:
插到尾部的判断条件不正确。
遍历链表到尾部时跳出while循环,但此时尾部记录的姓名未经判断条件检验,可能大于要添加的记录或重名。
将插入尾部的判断条件改为p2==tail&
=0
5.问题:
添加或修改名片时,若其中某项信息为空,保存后再打开文件,在页面上该项显示了下一项的信息;
若某项信息为中间有空格的字符串,如“BillGates”,保存后再打开,该项只显示Bill,下一项显示Gates。
ifstream对象fin在读取字符串时以空格判断读取结束,所以一次只能读取一个单词。
当信息为空时,fin直接忽略掉它,读取下一项非空信息。
解决方法:
使用fin.getline函数,如fin.getline(p2->
),读取字符串直到遇到’\t’为止。
相应地,在向文件中写入信息时,要使用
fout<
<
<
p->
data.Name<
'
data.Phone。
6.3设计心得和感受:
第一次编写较大的程序,和以往的小程序设计相比,难度有很大提升。
在编程的过程中,出现了很多困难和bug,最初对按姓名顺序添加名片等的算法设计也不够完善,因为没有系统学过C++和MFC造成的知识短缺。
但自己坚信:
真正的强者,志当强毅,意当慷慨,以自信的微笑迎接生活的每一个挑战!
但自己坚持不懈的投入其中,详细全面地考虑算法的每个细节,一步步的调试,观察各个指针的移动和指向,一个问题一个问题地解决,一步步地完善程序,当程序能够成功运行时,喜悦的心情油然而生!
。
书是智慧的源泉。
虽然自己缺少C++和MFC的知识,但通过查阅相关资料,自己还是在短期内掌握了很多知识。
在以后的工作中,也许我们曾经学过的知识不断过时,我们不断遇到未知的事物,但书会一直陪伴我们成长,化作自由飞翔的翅膀,通往峰巅的阶梯!
全面深入的思考会使人事半功倍。
如果自己在设计算法时能考虑的再详细点,很多错误都可以避免。