通讯录这东西,相信大家日常生活中都会见到。我们可以联想一下,既然我们要实现通讯录,那么就要搞清楚通讯录里面有什么。这里面有联系人名字,联系人号码(这些是属性),还有简单的一些功能,比如说添加联系人,删除联系人,查找联系人,当你发现号码错误的时候,就需要修改联系人号码了(我们查找联系人一般都是根据名字来查找),这四个都是基本的功能,实现以上三个操作后,我们还可以浏览通讯录,看看通讯录里面有什么,最后就是退出通讯录了。
说到联系人,这里面有属性,有功能,我们就需要建立一个Person类,专门写这些东西。对于那些功能来说,添加,删除,修改,查找啥的,就需要用链表来实现了,因此呢,在此之前我们就需要写出一个链表类来供我们使用了。
链表分为单链表,双链表,循环链表。 对于通讯录我们就使用单链表吧。那我先简单介绍一下链表吧。链表由结点和指针构成,结点又分为数据域和指针域,数据域用来存放数据的,而指针域是用来指向其它结点,单链表的结点只有一个指针域,双链表有两个,它们最后一个结点的指针域指向空,但是循环链表最后一个结点的指针域指向头结点。
首先我们需要定义结点类,而结点类嘛就有数据域和指针域,在通讯录里面我们的结点的数据就是联系人类了。
class Node
{
public:
Person data; //数据域,把他们放在public里面是为了方便后面的赋值
Node *next; //指针域
void printNode()
{
cout<
然后呢对于链表,我们就需要两个属性,一个是结点类,一个是链表长度。
private:
Node *m_list;
int length;
链表还需要一些功能函数,最基本的肯定是构造函数和析构函数,在通讯录里面呢,我们需要遇到添加,删除,根据姓名查找,因此我们可以定义这些函数:
构造函数和析构函数:
List() //构造函数
{
m_list=new Node; //构造函数中定义头结点 ,头结点的数据域无意义,不算在length里面
// m_list->data=0;
m_list->next=NULL;
length=0;
}
void ClearList()//清空线性表
{
Node *currentNode=m_list->next;
while(currentNode!=NULL)
{
Node *temp=currentNode->next;
delete currentNode;
currentNode = temp;
}
m_list->next=NULL;
}
~List()
{
ClearList(); //清空链表的函数
delete m_list;
m_list=NULL;
}
根据名字找到结点在链表当中的位置:
int LocateElem(string pname)
{
Node *currentNode=m_list;
int count=0;
while(currentNode->next!=NULL)
{
currentNode=currentNode->next;
if(currentNode->data.name==pname)
{
return count;
}
count++;
}
return -1;
}
获取链表当中某个位置的结点信息:
bool GetElem(int i,Node *pNode) //需要找到头结点
{
if(i<0||i>=length)
{
return false;
}
Node *currentNode=m_list;
for(int k=0;k<=i;k++)
{
currentNode=currentNode->next;
}
pNode->data=currentNode->data; //把相应位置结点的数据赋值给定义的pNode
return true;
}
链表添加与删除结点:
bool ListInsert(int i,Node *pNode) //从指定位置插入元素
{
if(i<0||i>length)
{
return false;
}
Node *currentNode = m_list;
for(int j=0;jnext;
}
Node *newNode=new Node;
if(newNode==NULL)
{
return false;
}
newNode->data=pNode->data;
newNode->next=currentNode->next;
currentNode->next=newNode;
length++;
return true;
}
bool ListDelete(int i,Node *pNode) //删除指定位置的元素
{
if(i<0||i>=length)
{
return false;
}
Node *currentNode=m_list;
Node *beforeNode=NULL;
for(int k=0;k<=i;k++)
{
beforeNode=currentNode;
currentNode=currentNode->next;
}
beforeNode->next=currentNode->next;
pNode->data=currentNode->data;
delete currentNode;
currentNode=NULL;
length--;
return true;
}
bool ListInsertTail(Node *pNode) //插入到最后一个位置
{
Node *currentNode = m_list;
while(currentNode->next!=NULL)
{
currentNode=currentNode->next;
}
Node *newNode=new Node;
if(newNode==NULL) //判断插入是否成功
{
return false;
}
newNode->data=pNode->data;
newNode->next=NULL;
currentNode->next=newNode;
length++; //要确保插入成功才加
return true;
}
既然我们需要浏览通讯录,那么我们就需要把链表每一个结点的数据输出就行了
链表遍历输出:
void ListTraverse()
{
Node *currentNode=m_list;
while(currentNode->next!=NULL)
{
currentNode=currentNode->next;
currentNode->printNode();
}
}
需要注意的是,我们结点当中的数据是联系人类,在联系人类当中,赋值,输出,输入,判断相等都需要进行运算符的重载。
class Person
{
friend ostream &operator<<(ostream &out,Person &p) //友元函数
{
out<name=p.name;
this->number=p.number;
return *this;
}
bool operator==(Person &p)
{
if(this->name==p.name&&this->number==p.number)
{
return true;
}
return false;
}
};
为了让通讯录看起来好看些,我们可以用菜单实现,因此可以定义一个菜单函数:
int Menu()
{
cout<<"请选择功能:"<>order;
return order;
}
对于添加联系人,我们就可以把输入的新联系人的信息赋值给新结点,然后利用链表添加函数进行添加:
void add(List *list)
{
Node node;
Person person;
cout<<"请输入联系人姓名:";
cin>>person.name;
cout<>person.number;
cout<ListInsertTail(&node);
}
对于删除联系人,我们可以通过姓名找到该结点在链表当中的位置,然后利用链表删除函数就可以了:
void deleteperson(List *list,string pname)
{
int m=list->LocateElem(pname);
Node node;
list->ListDelete(m,&node);
}
对于查找联系人,也可以通过姓名找到结点的位置,输出信息就行了。
void pfind(List *list,string pname)
{
int m=list->LocateElem(pname);
Node node;
list->GetElem(m,&node);
node.printNode();
}
list->ListTraverse();
修改联系人:先找到该名字对应结点的位置,然后在定义一个新结点修改信息,删除原结点,插入新结点即可:
void alter(List *list,string pname)
{
int m=list->LocateElem(pname);
Node node;
Node temp;
list->GetElem(m,&node);
string pnumber;
cout<<"请输入修改的号码:";
cin>>pnumber;
node.data.number=pnumber;
list->ListDelete(m,&temp);
list->ListInsert(m,&node);
}
如果读者有兴趣看源代码的话可以点击以下链接
https://blog.csdn.net/weixin_44346470/article/details/98640585