课程设计题目2

本文介绍了使用数据结构知识,特别是双链表,来设计一个个人通讯录管理软件的过程。软件包括输入、输出、插入、删除、查询和修改等功能。通过定义结构体和重载运算符实现通讯录的操作,如按姓名查找、删除和修改联系人信息。此外,文章还讨论了逻辑结构、存储结构设计以及算法设计,包括时间复杂度和空间复杂度分析。
摘要由CSDN通过智能技术生成


一. 问题描述
李刚是一爱折腾的人,当然爱折腾的人一. 问题描述
李刚是一爱折腾的人,当然爱折腾的人均有梦想,他想当中国的盖次呢。可不,现在个人好友信息多了,复杂了,他想制作一个个人通讯录的制作管理软件。 刚好这个学期学了数据结构课,所以他准备使用数据结构知识来实现了。并考虑使用双向链表作数据结构。
1、每个好友信息包含姓名、性别、住址、邮编、几岁、电话、QQ、微信帐号、生日等。
2、作为一个完整的系统,应具有友好的界面和较强的容错能力。
二. 问题分析
通讯录的制作,为了实现数据的输入、输出、插入、删除、查询的功能。程序的基本功能为:建立通讯者信息,包括姓名、编号、联系方式、生日添加新的通讯者信息;按姓名查询某个通讯者的信息;按姓名删除某个通讯者的信息;输出显示通讯录的所有信息。
在这里我选择运用双链表进行储存。双链表是在单链表的每个节点中再设置一个指向其前驱节点的指针域。双链表是一种对称结构,对于储存通讯录来说比较方便。
(1)内容:
1、通讯录内容包括:编号、姓名、联系方式、生日
(2)功能描述
1、遍历通信录。可以查看通信录中所有通信录成员的记录,该功能由函数void PrintFromHead()实现
2、插入新联系人功能。用户可以输入以上所有内容,建立一个新的通信记录。
3、删除功能。把旧的联系人进行删除释放储存空间
4、查询功能。最重要的功能,具有姓名查询的具体功能
5、修改功能。用户可以根据需要,对任意的某个联系人的每一项信息
进行修改。
6、退出系统
三. 逻辑结构和存储结构设计
从题目的要求中,我们可以看到题目要求我使用双链表来完成这次的课程设计,因此,这次的逻辑结构为线性表。线性表是一种最基本最简单的数据结构,数据元素之间仅具有单一的前驱和后驱关系。
由于这次的题目是构造一个通信录,需要插入和删除,查询和修改等功能,因此顺序表是静态存储分配并不适合,因此在这里选取链表来克服顺序表的缺点。
链表是用一组任意的存储单元存放线性表的元素,其中,双链表是在单链表的每个结点中再设置一个指向其前驱结点的指针域。在链表中实现插入和删除操作,无需移动结点,在将工作指针指向合适的位置后,仅需修改节点之间的链接关系,所以在通信录这次的题目中使用双链表比较合理。

四. 算法设计
(1) 总结构框架图
 

(2)详细算法设计分析
1、数据类型定义
在这里我定义结构类型和结构变量。
struct Data
{
char num[5],sex[4],pho[18],bir[5];
};
本系统运用链式存储结构,定义了头节点和尾结点:
Person* head;//头
Person* tail;//尾
int size;
2、系统主要子程序详细设计分析
①重载函数,由于字符串与字符串之间不能直接进行比较,在后面进行查找时会比较麻烦,因此,在这里进行运算符”=”,”<”,”>”等进行重载,使字符串能够之间能够进行比较,减少后面程序的复杂度。
void operator=(char* b) /*赋值重载*/
{
len=strlen(b);
for(int i=0;
i<=len;i++)
nam[i]=b[i]; }
bool operator==(char * str) //通配符的比较
{
int l=strlen(nam);
for(int i=0; i<l ;i++)
{
if(str[i]=='?')
continue;
if(str[i]=='*')
return true;
if(str[i]!=nam[i])
return false;
}
return true;
}
bool operator<=(Name a) /*比较函数*/
{
if(strcmp(nam,a.nam)<=0)
return true;
return false;
}
bool operator>=(Name a)
{
if(strcmp(nam,a.nam)>=0)
return true;
return false;
}

②建立双链表的函数,主要用来建立通讯录建立,定义了2个结构体指针*head,*tail。
class DoubleLinkList
{
Person* head;//头
Person* tail;//尾
int size;
public:
DoubleLinkList() //构造
~DoubleLinkList() //析构
bool IsEmpty() //空判断
void PrintFromHead() //从头到尾的遍历
bool InsertAtSort(Data a,char* k) //插入元素
void SeekForName(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; }
④链表元素的插入,可以插入多个元素,插入的元素之间的关系用指针表示,无需移动结点,仅需修改结点之间的连接关系。
bool InsertAtSort(Data a,char* k) //插入元素
{
Person * temp= new Person(a,k);
Name nam(k);
if(temp==NULL)
{
cout<<"对不起,内存申请失败\n";
return false; }
if(size==0)
{
tail=temp;
head=temp;
size++;
return true; }
⑤查找函数通过比较所要查找的结点中的姓名,建立结构体指针*temp=head,比较a元素的字符串是否相同,相同则输出查找结果。
void SeekForName(char* a)//在表中查找a元素
{
Person*temp=head;
int i=1;
while(temp)
{
if(temp->name==a)
{
cout<<"\n下面是系统为您找到的信息:\n";
printTitle();
temp->show();
cout<<endl;
cout<<"第"<<i<<"个";
cout<<endl;}
temp=temp->p2;
i++; }
cout<<"查找完毕"<<endl; }
⑥void Remove()函数用来删除信息,先按姓名查找要删除的信息,比较所要查找的节点中的姓名。找到之后释放姓名所在的结点。如果不存在则输出:“没有要删除的对象”。此函数分3种情况,删除头结点,删除中间或尾结点。所需算法不一样。在这里我也运用了cin.good(),cin.clear()这两个函数,在输入错误时会停止操作,并清除错误标志。
void Remove(char* nam) /*删除链表中的a元素*/
{
Person*temp=head;
while(temp)
{
if(temp->name==nam)
break;
temp=temp->p2; }
if(temp == NULL)
{
cout<<"\n\t(您要删除的联系人不存在,操作无法完成。。。)\n";
return;
} else /*找到了要删除的元素*/
{ int choose;
char buffer[SIZE];
cout<<"\n您确认要删除该联系人:"<<temp->name<<"\n-->请输入:\n\t"<<"1.是 或者 2.否:"<<endl;
cin>>choose;
while(!cin.good()||(choose!=1)&&(choose!=2))
{
if(!cin.good())//清内存
{
cin.clear();
cin.getline(buffer,SIZE);}
cout<<"输入错误"<<endl;
system("cls");
cout<<"\n您确认要删除该联系人:"<<temp->name<<"\n-->请输入:\n\t"<<"1.是 或者 2.否:"<<endl;
cin>>choose;}
cin.getline(buffer,SIZE);
if(choose==2)
{
cout<<"联系人未被删除\n";
return;
}
if(size==1)//置空
{
head=NULL;
tail=NULL;
size=0; }
else if(temp==head)
{
head=head->p2;
head->p1=NULL;
size--;
delete[]temp; }
else if(temp==tail)
{
tail=tail->p1;
tail->p2=NULL;
size--;
delete[]temp; }
else
{
Person*temp2=temp->p1,*temp3=temp->p2;
temp2->p2=temp3;
temp3->p1=temp2;
size--;
delete[]temp; }
cout<<"\n\t(该联系人被成功删除)\n"; } }
⑦更改通讯录中的信息,运用这个函数时先按姓名查找要更改的信息,比较所要查找的结点中的姓名,找到之后再重新输入编号、姓名、单位、通信、地址、邮箱、联系、电话,并且覆盖原来的内容。
void Modify(char* nam)//修改
{
Person*temp=head;
int choose;
Data t;
char buffer[SIZE],str[SIZE];
while(temp) //查找
{
if(temp->name==nam)
break;
temp=temp->p2; }
if(temp == NULL)
{ cout<<"\t(您要修改的联系人不存在,操作无法完成。。。)\n";
return; }
cout<<"请输入您更正后的信息:";
cout<<"\n\t\t格式为:序号 姓名 性别 联系方式 生日\n\t\t -->";
cin>>t.num>>str>>t.sex>>t.pho>>t.bir;
Person modi(t,str); //更新的联系人信息
cin.getline(buffer,SIZE); //去掉多余输入
cout<<endl; //开始修改
cout<<"您确认要更改该联系人信息:\n";
temp->show();
cout<<endl;
modi.show();
cout<<"\n请输入:"<<" 1.YES or 2.NO:"<<endl;
cin>>choose;
while(!cin.good()||(choose!=1)&&(choose!=2))
{
if(!cin.good())
{
cin.clear();
cin.getline(buffer,SIZE);
}
cout<<"输入错误,请输入1 或者 2"<<endl;
system("cls"); //清屏
cout<<"您确认要更改该联系人信息:\n";
temp->show();
cout<<endl;
modi.show();
cout<<"\n请输入:"<<" 1.YES or 2.NO:"<<endl;
cin>>choose; }
cin.getline(buffer,SIZE);
if(choose==2)
{
cout<<"联系人未被修改\n";}
else{
temp->set(t,str);
cout<<"联系人信息已近被更正为:\n";
temp->show();}
}
};

五. 时间复杂度和空间复杂度分析
和单链表类似,双链表一般也由头指针唯一确定,增加头结点也能使双链表的某些操作变得方便。这时,由书本上可知,按值查找:与输入实例有关,平均时间复杂度均为O(n),双链表上的插入和删除时间复杂度均为O (1)。空间复杂度为O(n)。


六.源代码
#include<iostream>
#include<string>
#include<fstream>
using namespace std;

//------------------------------------------------------------------------
---


typedef struct person//定义一个结构体类型
{
char name[15];
char sex[30];
char age[20];
char street[20];
char eip[20];
char phone[20];
char qq[20];
char weixin[20];
char birth[20];
}person;

typedef struct Dulnode//双向链表结点结构类型定

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值