一. 问题描述
李刚是一爱折腾的人,当然爱折腾的人均有梦想,他想当中国的盖次呢。可不,现在个人好友信息多了,复杂了,他想制作一个个人通讯录的制作管理软件。 刚好这个学期学了数据结构课,所以他准备使用数据结构知识来实现了。并考虑使用双向链表作数据结构。
1、每个好友信息包含姓名、性别、住址、邮编、几岁、电话、QQ、微信帐号、生日等。
2、作为一个完整的系统,应具有友好的界面和较强的容错能力。
二. 问题分析
通讯录的制作,为了实现数据的输入、输出、插入、删除、查询的功能。程序的基本功能为:建立通讯者信息,包括姓名、编号、联系方式、生日添加新的通讯者信息;按姓名查询某个通讯者的信息;按姓名删除某个通讯者的信息;输出显示通讯录的所有信息。
在这里我选择运用双链表进行储存。双链表是在单链表的每个节点中再设置一个指向其前驱节点的指针域。双链表是一种对称结构,对于储存通讯录来说比较方便。
(1)内容:
1、通讯录内容包括:编号、姓名、联系方式、生日
(2)功能描述
1、遍历通信录。可以查看通信录中所有通信录成员的记录,该功能由函数voidPrintFromHead()实现
2、插入新联系人功能。用户可以输入以上所有内容,建立一个新的通信记录。
3、删除功能。把旧的联系人进行删除释放储存空间
4、查询功能。最重要的功能,具有姓名查询的具体功能
5、修改功能。用户可以根据需要,对任意的某个联系人的每一项信息
进行修改。
6、退出系统
三. 逻辑结构和存储结构设计
从题目的要求中,我们可以看到题目要求我使用双链表来完成这次的课程设计,因此,这次的逻辑结构为线性表。线性表是一种最基本最简单的数据结构,数据元素之间仅具有单一的前驱和后驱关系。
由于这次的题目是构造一个通信录,需要插入和删除,查询和修改等功能,因此顺序表是静态存储分配并不适合,因此在这里选取链表来克服顺序表的缺点。
链表是用一组任意的存储单元存放线性表的元素,其中,双链表是在单链表的每个结点中再设置一个指向其前驱结点的指针域。在链表中实现插入和删除操作,无需移动结点,在将工作指针指向合适的位置后,仅需修改节点之间的链接关系,所以在通信录这次的题目中使用双链表比较合理。
四. 算法设计
(1)总结构框架图
(2)详细算法设计分析
1、数据类型定义
在这里我定义结构类型和结构变量。
struct Data
{
charnum[5],sex[4],pho[18],bir[5];
};
本系统运用链式存储结构,定义了头节点和尾结点:
Person*head;//头
Person*tail;//尾
int size;
2、系统主要子程序详细设计分析
①重载函数,由于字符串与字符串之间不能直接进行比较,在后面进行查找时会比较麻烦,因此,在这里进行运算符”=”,”<”,”>”等进行重载,使字符串能够之间能够进行比较,减少后面程序的复杂度。
void operator=(char* b) /*赋值重载*/
{
len=strlen(b);
for(inti=0;
i<=len;i++)
nam[i]=b[i]; }
booloperator==(char * str) //通配符的比较
{
intl=strlen(nam);
for(inti=0; i<l ;i++)
{
if(str[i]=='?')
continue;
if(str[i]=='*')
returntrue;
if(str[i]!=nam[i])
returnfalse;
}
returntrue;
}
booloperator<=(Name a) /*比较函数*/
{
if(strcmp(nam,a.nam)<=0)
returntrue;
returnfalse;
}
booloperator>=(Name a)
{
if(strcmp(nam,a.nam)>=0)
returntrue;
returnfalse;
}
②建立双链表的函数,主要用来建立通讯录建立,定义了2个结构体指针*head,*tail。
class DoubleLinkList
{
Person*head;//头
Person*tail;//尾
int size;
public:
DoubleLinkList() //构造
~DoubleLinkList() //析构
boolIsEmpty() //空判断
voidPrintFromHead() //从头到尾的遍历
bool InsertAtSort(Data a,char* k) //插入元素
voidSeekForName(char* a)//在表中查找a元素
void Remove(char* nam) /*删除链表中的a元素*/
void Modify(char* nam)//修改
③显示双链表中所有结点的信息,查看通信录的所有记录,这里运用了头到尾的遍历,如果双链表为空,则输出为空链表,此函数主要是通过结构体指针实现的。
void PrintFromHead() //从头到尾的遍历
{
Person*temp=head;
if(temp==NULL)
{
cout<<"这是一个空链表"<<endl;
return; }
printTitle();
while(temp->p2!=NULL)
{
temp->show();
cout<<endl;
temp=temp->p2; }
temp->show();
cout<<endl; }
④链表元素的插入,可以插入多个元素,插入的元素之间的关系用指针表示,无需移动结点,仅需修改结点之间的连接关系。
boolInsertAtSort(Data a,char* k) //插入元素
{
Person* temp= new Person(a,k);
Namenam(k);
if(temp==NULL)
{
cout<<"对不起,内存申请失败\n";
returnfalse; }
if(size==0)
{
tail=temp;
head=temp;
size++;
return true; }
⑤查找函数通过比较所要查找的结点中的姓名,建立结构体指针*temp=head,比较a元素的字符串是否相同,相同则输出查找结果。
void SeekForName(char* a)//在表中查