【C++课程设计】基于单向链表的通讯录管理程序


通讯录效果图

问题描述

该设计采用菜单作为应用程序的主要界面,用控制语句来改变程序执行的顺序,控制语句是实现结构化程序设计的基础。该设计的任务是利用一个简单实用的菜单,通过菜单单项进行选择,实现和完成通讯录管理中常用的几个不同的功能。通讯者所包含信息请自行设定

任务要求

菜单内容:
(0)通讯录链表的建立
(1)通讯者结点的插入
(2)通讯者结点的查询
(3)通讯者结点的删除
(4)通讯录链表的输出
(5)退出管理系统
设计要求:
使用0-5来选择菜单项,可扩展功能。
功能函数设计
5个不同功能的算法实现编程题,目的是练习利用链表结构来解决实际应用问题的能力,进一步理解和熟悉线形表的链式存储结构


设计思想

将数据存储的链表,用户交互界面,核心测试类分成三大模块。链表,界面作为头文件,引入到测试类中,实现功能的分块整合。不同模块中有具体的实现,通过接口类,暴露实现方法名称,隐藏实现细节。

功能模块

1,数据存储

以简单单向列表的形式来存储数据,链表实现类继承接口类,并实现其中的方法。

2,交互界面

通过字符画的形式构建交互界面,并将绘制界面的各个方法,封装入界面绘制工具类中,定义在“MYGUI.h”的头文件中。

3,主类功能匹配与整合

将数据存储模块“Link.h”和交互界面“MYGUI.h”载入主类中,通过子类的工具类,根据用户的不同操作匹配调用各个头文件中的方法,并整合流程与方法。


在这里插入图片描述
通讯录程序模块图

程序流程图

在这里插入图片描述

程序流程图

源码实现

【1】Link.h

#include<iostream>
#include<string>
#include<fstream>
using namespace std;
static int counts=0;//链数 
static int foot;//索引 
class ILink{//接口类,暴露方法,隐藏细节 
	protected:
		virtual void add(string data)=0;
		virtual int count()=0;
		virtual bool isEmpty()=0;
		virtual string get(int index)=0;
		virtual void set(int index)=0;
		virtual void toArray()=0;
		virtual bool contains(string data)=0;
		virtual void remove(int index)=0;
		virtual void clean()=0;
		virtual void fileOut(char* path)=0;
		virtual void fileIn(char* path)=0; 
}; 
class Node{//结点类 
	public:
		string data;//结点数据 
		Node *next=NULL;//保留下一节点 
		Node(string data){
			this->data=data;
		}
		//Node类对外支持的方法,主要使用了递归 
		void addNode(Node* newNode){
			if(this->next==NULL){
				this->next=newNode;
			}else{
				this->next->addNode(newNode);
			}
		}
		void toArrayNode(){
			cout<<"["<<foot++<<"]"<<this->data<<endl;
			if(this->next!=NULL){
				this->next->toArrayNode();
			}
			
		}
		string getNode(int index){
			if(foot++==index){
				return this->data;
			}else{
				return this->next->getNode(index);
			}
		}
		void setNode(int index,string data){
			if(foot++==index){
				this->data=data;
			}else{
				this->next->setNode(index,data);
			}
		}
		bool containsNode(string data){
			if(this->data==data){
				return 1;
			}else if(this->next==NULL){
				return 0;
			}else{
				return this->next->containsNode(data);
			}
		}
		void removeNode(Node* previous,int index){//一定要接受指针,进行地址传递,不能进行值传递 
			if(foot++==index){
				previous->next=this->next;
			}else if(this->next!=NULL){
				this->next->removeNode(this,index);
			}
		}
		void fileOutNode(char* path)throw (int){
			ofstream file;
			file.open(path,ios::app);
			if(!file){
				throw 0;
				return ;
			}
			file<<this->data<<endl;
			if(this->next!=NULL){
				this->next->fileOutNode(path);
			}else{
				file.close();//关闭文件流 
			}
		}
		
};
class Link:public ILink{
	private:
		Node *root=NULL;//初始化根节点 
	public:
		~Link(){
			delete root;
		}
		//Link类对外支持的方法 
		void add(string data){//add的两种形式:向根节点添加,向子节点添加 
			Node* newNode=new Node(data);
			if(this->root==NULL){ 
				this->root=newNode;
			}else{
				this->root->addNode(newNode);
			}
			counts++;//链数加一 
		} 
		int count(){
			return counts;
		}
		bool isEmpty(){
			return counts==0;
		}
		void toArray(){
			if(this->isEmpty()){
				cout<<"链表中没有数据"<<endl;
			}
			foot=1;
			root->toArrayNode();
		}
		string get(int index) throw (int){
			if(index>counts|index<=0){//两个判断都要进行,所以不用短路或“||” 
				throw 0;//索引无效 
				return "ERROR";
			}
			foot=1;//初始化索引 
			return this->root->getNode(index);
		}
		void set(int index)throw (int){
			if(index>counts|index<=0){//两个判断都要进行,所以不用短路或“||” 
				throw 0;//索引无效 
				return;
			}
			string str[4];
			cout<<"通讯者 [姓名]:";
			cin>>str[0];
			cout<<"通讯者 [电话]:";
			cin>>str[1];
			cout<<"通讯者 [QQ]:";
			cin>>str[2];
			str[3]="[姓名]:"+str[0]+" [电话]:"+str[1]+" [QQ]:"+str[2];
			foot=1;//初始化索引 
			this->root->setNode(index,str[4]);
		}
		bool contains(string data){
			return this->root->containsNode(data);
		}
		void remove(int index) throw (int){//remove的两种形式:输出根节点,删除子节点 
			if(index>counts|index<=0){//两个判断都要进行,所以不用短路或“||” 
				throw 0;//索引无效 
				return;
			}
			if(index==1){
				this->root=this->root->next;
				counts--;//链数减一 
			}else{
				foot=1;
				this->root->removeNode(this->root,index);	
				counts--;
			}
		}
		void fileOut(char* path){//链表导出 
			if(this->isEmpty()){
				cout<<"链表中没有数据"<<endl;
			}
			root->fileOutNode(path);
		} 
		void fileIn(char* path)throw(int){//文件导入 
			ifstream file(path);
			string data;
			if(!file){
				throw 0;
				return;
			}
			getline(file,data);//整行导入 
			while(!file.eof()&&data!=""){//判断文件结尾 
				this->add(data);
				getline(file,data);//整行导入 
			}
			file.close(); 
		}
		void clean(){//清空根节点 
			this->root=NULL;
			counts=0;
		}
};

【2】MYGUI.h

#include<iostream>
#include<string> 
#include<cstdlib>
using namespace std;
class MYGUI{//绘制界面工具类 
	public:
		static void start(){//设置窗口大小 
			system("mode con cols=55 lines=36");
		}
		static void menu(){//画菜单 
		cout<<" +-----------------------------------------------------+\n";
        cout<<" |                                                     |\n";
        cout<<" |        0  000000    0           00000000            |\n";
        cout<<" |         0   0  0     0 00000           0            |\n";
        cout<<" |              00         0  0     0000000            |\n";
        cout<<" |           0000000       0  0           0            |\n";
        cout<<" |        00 0  0  0  000  0  0   00000000000          |\n";
        cout<<" |         0 0000000    0 00000        0               |\n";
        cout<<" |         0 0  0  0    0  0  0    0   0   0           |\n";
        cout<<" |         0 0000000    0  0  0     0 000 0            |\n";
        cout<<" |         0 0  0  0    0  0  0      0 0 0             |\n";
        cout<<" |         0 0  0 00    00 0  0 0   0  0  0            |\n";
        cout<<" |         0            0  0   00 00   0   00          |\n";
        cout<<" |        0 000000000      0    0     00               |\n";
        cout<<" |                                                     |\n";
        cout<<" |-----------------------------------------------------|\n";
        cout<<" |                                                     |\n";
        cout<<" |                      [SoftMenu]                     |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (0) 通讯录链表的建立                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (1) 通讯者链表的导入                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (2) 通讯者结点的插入                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (3) 通讯者结点的查询                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (4) 通讯者结点的修改                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (5) 通讯者结点的删除                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (6) 通讯录链表的清空                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (7) 通讯录链表的打印                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (8) 通讯录链表的导出                 |\n";
        cout<<" |                                                     |\n";
        cout<<" |                (9) 退出管理系统                     |\n";
        cout<<" |                                                     |\n";
        cout<<" |                                                     |\n";
		cout<<" +-----------------------------------------------------+\n";	
		cout<<"【请输入功能选项】:"<<flush;//flush用于刷新此处的缓冲区,防止输入数据延滞	  
		}
		static void tip(string tip){//画提示信息
			cout<<endl;
			cout<<" +-----------------"<<tip<<"----------------+\n";
			cout<<" |                                                     |\n";
		} 
		static void tipMenu(){
			cout<<" |                                                     |\n";
			cout<<" +-----------------------------------------------------+\n";
			cout<<" |(0)创建链表   (1)导入链表   (2)插入结点   (3)查询结点|\n";
			cout<<" |(4)修改结点   (5)删除结点   (6)清空链表   (7)打印链表|\n";
			cout<<" |(8)导出链表   (9)退出系统                            |\n";
			cout<<" +-----------------------------------------------------+\n";
			cout<<"【请输入功能选项】:"; 
		} 
		 
};

【3】通讯录.cpp

#include<iostream>
#include<string>
#include"MYGUI.h"//载入界面绘制类 
#include"Link.h"//载入链表,提供数据存储支持 
using namespace std;
int option;//输入选项 
Link *plink=NULL;//链表指针 
char input[2];//用户输入值,用于验证 

class Util{//操作工具类 
	public:
		//输入验证,确保数据为0-5整数,验证通过返回解码后的整数,否则返回-1 
		static int inputExam(char* input){
			if(input[0]>='0'&&input[0]<='9'&&input[1]==NULL){
				return input[0]-48;
			}
			return -1;
		} 
		//输入选项编号,通过switch来匹配各个选项的功能 
		static void option(int option){
			switch(option){
				case 0:{ //创建链表 
					Util::creatLink();
					break;
				} 
				case 1:{//导入文件 
					Util::importLink();
					break;
				}
				case 2:{//插入结点 
					Util::insertNode();
					break;
				}					
				case 3:{//查询结点
					Util::findNode();
					break;
				}
				case 4:{//修改节点 
					Util::alterNode();
					break;
				}					
				case 5:{//删除结点
					Util::deleteNode();
					break;
				}
				case 6:{//清空链表 
					Util::cleanLink();
					break;
				}					
				case 7:{//输出链表 
					Util::showLink();
					break;
				}
				case 8:{//链表导出 
					Util::exportLink();
					break;
				}		
			}
		}
		static void creatLink(){
			MYGUI::tip("(0) 通讯录链表的建立");
			if(plink!=NULL){
				char str;
				cout<<"【已存在通讯录链表,是否重新创建(y/n)】:"<<flush;
				cin>>str;
				if(str=='y'){
					plink->clean(); //并没有重新创建新的链表,只不过是将原有链表清空了,这样节约内存开支 
					cout<<"【创建通讯录链表成功】\n";
					MYGUI::tipMenu();
				}else if(str=='n'){
					MYGUI::tipMenu();
				}else{
					cout<<"【输入错误,请输入(y/n)】\n";
					Util::option(0);
				}
			} else{
				plink=new Link();
				cout<<"【创建通讯录链表成功】\n";
				MYGUI::tipMenu();
			}			
		} 
		static void importLink(){
			MYGUI::tip("(1) 通讯录链表的导入"); 
			if(plink!=NULL){
					char path[100]; //支持char[100]范围内的路径 
					cout<<"【请输入导入文件路径名称(.txt)】:";
					cin>>path; 
					try{
						plink->fileIn(path); 
						cout<<"【导入文件成功】\n";
						MYGUI::tipMenu();
					}catch(int){
						cout<<"【文件打开失败,检查输入路径】\n";
						MYGUI::tipMenu();
					}
			}else{
				cout<<"【尚未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			}			
		}
		static void insertNode(){
			MYGUI::tip("(2) 通讯者结点的插入");
			if(plink!=NULL){
				string str[4];//存储输入的数据 
				cout<<"【插入第"<<plink->count()+1<<"个通讯者信息】\n";
				cout<<"通讯者 [姓名]:";
				cin>>str[0];
				cout<<"通讯者 [电话]:";
				cin>>str[1];
				cout<<"通讯者 [QQ]:";
				cin>>str[2];
				str[3]="[姓名]:"+str[0]+" [电话]:"+str[1]+" [QQ]:"+str[2];
				plink->add(str[3]);
				cout<<"【第"<<plink->count()<<"个通讯者信息录入完成】\n";
				MYGUI::tipMenu(); 
			}else{
				cout<<"【尚未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			}			
		}
		static void findNode(){
			MYGUI::tip("(3) 通讯者结点的查询"); 
			if(plink!=NULL){
				if(plink->isEmpty()){
					cout<<"【尚未录入通讯者信息,请录入】\n";
					MYGUI::tipMenu();
				}else{
					int index;//输入的查询索引 
					string data;//存储查询得到的信息 
					cout<<"【请输入要查询通讯者的编号】:";
					cin>>index;
					try{//异常处理 
						data=plink->get(index);
						cout<<"【查询结果】\n";
						cout<<data<<endl;
						MYGUI::tipMenu();
					}catch(int){
						cout<<"【查询失败,检查编号】\n";
						MYGUI::tipMenu();
					}		
				}
			}else{
				cout<<"【尚未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			} 			
		}
		static void alterNode(){
			MYGUI::tip("(4) 通讯者结点的修改"); 
			if(plink!=NULL){
				if(plink->isEmpty()){
					cout<<"【尚未录入通讯者信息,请录入】\n";
					MYGUI::tipMenu();
				}else{
					int index;
					cout<<"【请输入需要修改通讯者的编号】:";
					cin>>index;
					 try{
					 	plink->set(index); 
					 	cout<<"【修改成功】\n";
					 	MYGUI::tipMenu();
					 }catch(int){
					 	cout<<"【修改失败,检查编号】\n";
					 	MYGUI::tipMenu();
					 }
				}
			}else{
				cout<<"【尚未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			}
		} 
		static void deleteNode(){
			MYGUI::tip("(5) 通讯者结点的删除"); 
			if(plink!=NULL){
				if(plink->isEmpty()){
					cout<<"【尚未录入通讯者信息,请录入】\n";
					MYGUI::tipMenu();
				}else{
					int index;
					cout<<"【请输入需要删除通讯者的编号】:";
					cin>>index; 
					try{//异常处理 
						plink->remove(index);
						cout<<"【删除成功】\n";
						MYGUI::tipMenu();
					}catch(int){
						cout<<"【删除失败,检查编号】\n";
						MYGUI::tipMenu();
					}
				}
			}else{
				cout<<"【尚未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			}			
		}
		static void cleanLink(){
			MYGUI::tip("(6) 通讯者链表的清空"); 
			if(plink!=NULL){
				if(plink->isEmpty()){
					cout<<"【空链表,无需清空】\n";
					MYGUI::tipMenu();
				}else{
					plink->clean();
					cout<<"【清空成功】\n";
					MYGUI::tipMenu();
				} 
			} else{
				cout<<"【未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			}
		}
		static void showLink(){
			MYGUI::tip("(7) 通讯录链表的输出"); 
			if(plink!=NULL){
				if(plink->isEmpty()){
					cout<<"【未录入通讯者信息,请录入】\n";
					MYGUI::tipMenu();
				}else{
					cout<<"【输出结果】\n" ;
					plink->toArray(); 
					MYGUI::tipMenu();
				}
			}else{
				cout<<"【尚未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			}			
		}
		static void exportLink(){
			MYGUI::tip("(8) 通讯录链表的导出"); 
			if(plink!=NULL){
				if(plink->isEmpty()){
					cout<<"【尚未录入通讯者信息,请录入】\n";
					MYGUI::tipMenu();
				}else{
					char path[100]; //支持char[100]范围内的路径 
					cout<<"【请输入导出文件路径名称(.txt)】:";
					cin>>path; 
					try{
						plink->fileOut(path); 
						cout<<"【导出文件成功】\n"; 
						MYGUI::tipMenu();
					}catch(int){
						cout<<"【文件打开失败,检查输入路径】\n";
						MYGUI::tipMenu(); 
					}
				}
			}else{
				cout<<"【尚未创建通讯者链表,请创建】\n";
				MYGUI::tipMenu();
			}			
		}
};

int main(){
	MYGUI::menu();//画界面 
	cin>>input;
	option=Util::inputExam(input);
	while(option==-1){
		cout<<"【输入错误,请输入 0~9 范围类的整数】:";
		input[1]=NULL;//初始化input[1] 
		cin>>input;
		option=Util::inputExam(input);
	}
	while(option!=9){//循环输入 
		Util::option(option);
		cin>>input;
		option=Util::inputExam(input);//输入验证 
		while(option==-1){
			cout<<"【输入错误,请输入 0~9 范围类的整数】:";
			input[1]=NULL;//初始化input[1] 
			cin>>input;
			option=Util::inputExam(input);//输入验证 
		}
	}
	cout<<"\n【bye~】";//结束 
	return 0;
}

不足

没有统一的异常处理类,Link需要使用模板来增加链表存储数据类型,扩展链表用途。日后有时间再填。

课程设计报告与源码获取

【猛击此处】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值