C++链表实现简单通讯录

通讯录简单介绍

通讯录这东西,相信大家日常生活中都会见到。我们可以联想一下,既然我们要实现通讯录,那么就要搞清楚通讯录里面有什么。这里面有联系人名字,联系人号码(这些是属性),还有简单的一些功能,比如说添加联系人,删除联系人,查找联系人,当你发现号码错误的时候,就需要修改联系人号码了(我们查找联系人一般都是根据名字来查找),这四个都是基本的功能,实现以上三个操作后,我们还可以浏览通讯录,看看通讯录里面有什么,最后就是退出通讯录了。
说到联系人,这里面有属性,有功能,我们就需要建立一个Person类,专门写这些东西。对于那些功能来说,添加,删除,修改,查找啥的,就需要用链表来实现了,因此呢,在此之前我们就需要写出一个链表类来供我们使用了。
链表分为单链表,双链表,循环链表。 对于通讯录我们就使用单链表吧。那我先简单介绍一下链表吧。链表由结点和指针构成,结点又分为数据域和指针域,数据域用来存放数据的,而指针域是用来指向其它结点,单链表的结点只有一个指针域,双链表有两个,它们最后一个结点的指针域指向空,但是循环链表最后一个结点的指针域指向头结点。

分析与链表实现

首先我们需要定义结点类,而结点类嘛就有数据域和指针域,在通讯录里面我们的结点的数据就是联系人类了。

class Node
{
	public:
		Person data;             //数据域,把他们放在public里面是为了方便后面的赋值 
		Node *next;             //指针域
		void printNode()
		{
			cout<<data<<endl;
		} 
};

然后呢对于链表,我们就需要两个属性,一个是结点类,一个是链表长度。

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;j<i;j++)
			{
				currentNode=currentNode->next;
			} 
			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<<p.name<<" "<<p.number<<endl;
	}
	public:
		string name;
		string number;
		Person &operator=(Person &p)
		{
			this->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<<"请选择功能:"<<endl;
	cout<<"1.添加联系人"<<endl;
	cout<<"2.删除联系人"<<endl;
	cout<<"3.浏览通讯录"<<endl;
	cout<<"4.查找联系人"<<endl; 
	cout<<"5.修改联系人"<<endl;
	cout<<"6.退出通讯录"<<endl;
	cout<<"请输入:*****************************"<<endl;
	int order=0;
	cin>>order;
	return order; 
}

在这里插入图片描述
对于添加联系人,我们就可以把输入的新联系人的信息赋值给新结点,然后利用链表添加函数进行添加:

void add(List *list)
{
	Node node;
	Person person;
	cout<<"请输入联系人姓名:";
	cin>>person.name;
	cout<<endl;
	cout<<"请输入联系人电话号码:";
	cin>>person.number;
	cout<<endl;
	node.data=person;
	list->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

发布了22 篇原创文章 · 获赞 27 · 访问量 2855

猜你喜欢

转载自blog.csdn.net/weixin_44346470/article/details/98632997
今日推荐