数据结构课程设计-通讯录管理系统(C语言版)

##数据结构课程设计-通讯录管理系统

一,前言

自从上次C语言课设写完后,这次数据结构课设就写的游刃有余了,很快啊,不足三天就写完了它(年轻人不讲武德),如果你认真看过我之前写的C语言课程设计-球队管理系统,你就不难发现,这次数据结构的课设完全就是那篇直接改过来的,也就存储结构变了一下。
C语言课设在这里-----球队管理系统(C语言版)

废话先不多说,直接上完整代码:

二,直接上代码

#include
#include
#include
#include
typedef int ElemType;
typedef struct person{
     
	char num[10];//编号 
	char name[10];//姓名 
	char sex[10];//性别 
	char phone[10];//电话 
}personal;/*={};测试*/
typedef struct node
{
     
	person data;//数据域 
	struct node * next;//指针域 
}ListNode,* LinkList;
LinkList InitList();
LinkList Create(LinkList head);
void List(LinkList head);//显示所有记录 
void save(LinkList head);//保存到文件 
void Find(LinkList head);//按要求查找 
int GetLength(LinkList head);//总记录条数 
void Add(LinkList head);//增加新的记录 
void Alter(LinkList head);//修改 
void Delete(LinkList head); //删除 
void Statis_sex(LinkList head);//性别个数 
void Quit();//退出选单 
void Menu(LinkList head);//选单
//Creat模块已通过读取文件信息实现 
LinkList InitList()
{
     
	LinkList head=(LinkList)malloc(sizeof(ListNode));//创立头结点
	if(head==NULL)
	{
     
		printf("空间分配无效!");		
		exit(-1);//退出程序
	}
	head->next=NULL;
	return head;
}
LinkList Create(LinkList head)
{
     
    person LM;//接受文件数据 
    LinkList rear;
    rear=head;
    FILE *fp= fopen("file.txt","r");
    if(fp==NULL)
    {
     
        printf("打开文件失败!");
        return NULL; 
    }
     
   while(fscanf(fp,"%s%s%s%s",LM.num,LM.name,LM.sex,LM.phone)!=EOF)//处理到文件尾 
    {
       
       LinkList s=(LinkList)malloc(sizeof(ListNode));
       s->data=LM;
       s->next=NULL;
       rear->next=s;
       rear=s;
    }
    fclose(fp);
    return head;
} 
void List(LinkList head) {
     
	LinkList p;
	p = head->next;
	if (!p) //如果head指针为空说明链表为空
	{
     
		printf("\n链表为空!\n\n");
	}
	else
	{
     
		printf("\n通信录:\n\n");
		printf("编号	姓名	性别	电话 \n");
		while (p)  //循环将各个节点值输出
		{
     		
			printf("%s\t%s\t%s\t%s\n",p->data.num,p->data.name,p->data.sex,p->data.phone);//打印
			p = p->next;//此句放在打印后面,防止产生野指针 
		}
		Statis_sex(head);
		printf("\n返回主菜单\n");
		system("pause");//页面停留
		Menu(head);
	}
}
void save(LinkList head)
{
     
	LinkList rear;
	person LM;
	rear=head->next;//跳过头节点 
	FILE *fp;
	int i;
    if((fp=fopen("file.txt","wb"))==NULL)/*只打开或建立一个二进制文件,只允许写数据*/
	{
     
		printf("\n文件不存在!\n");
	}
	while(rear)//处理到文件尾 
    {
       
    	LM=rear->data;
    	fprintf(fp,"%s\t%s\t%s\t%s\n",LM.num,LM.name,LM.sex,LM.phone);
    	rear=rear->next;
    }
    fclose(fp);
}
void Find(LinkList head)
{
     
	int Loop=0;
	char name[10];
	printf("请输入要查询联系人的姓名[     ]\b\b\b\b\b\b");
	scanf("%s",name);
	LinkList rear=head->next; 
	while(rear)
	{
     
		if (strcmp(rear->data.name,name)==0) 
			{
     
				printf("编号	姓名	性别	电话 \n");
				printf("%s\t%s\t%s\t%s\n",rear->data.num,rear->data.name,rear->data.sex,rear->data.phone);
				Loop=1;
			}
		rear=rear->next;
	 }
	if(Loop==1)
		{
     
			printf("\n查询联系人成功!返回菜单\n");
			system("pause");
			Menu(head); 
	 	} 
	else
	{
     
		int n;
		printf("无此联系人!!!\n\n返回菜单(1) or 重新输入(2)[  ]\b\b\b");
	 	scanf("%d",&n);
	 	printf("\n");
		switch(n)
		{
     
			case 1:system("cls");Menu(head);break;
			case 2:system("cls");Find(head);break;
		}
	}
}
int GetLength(LinkList head)
{
     
	LinkList p=head->next;
	int i=0;
	while(p)
	{
     
		i++;
		p=p->next;

	}
	return i;
}//获取链表长度 
void Add(LinkList head)
{
      
	char c;
	person LM;
	LinkList p=head;
	printf("请输入新建联系人的信息\n\n编号	/姓名	/性别	/电话号码:\n");
	do
	{
     
		scanf("%s",LM.num);
		scanf("%s",LM.name);
		scanf("%s",LM.sex);
		scanf("%s",LM.phone);
		LinkList s=(LinkList)malloc(sizeof(ListNode));
		s->data=LM;
		s->next=NULL;
		while(p->next)
		{
     
			p=p->next;
		}
		p->next=s;
		save(head);
		printf("是否继续添加 y/n\n");
		scanf(" %c",&c);
	}while(c=='y'||c=='Y');
	printf("\n返回主菜单\n");
	system("pause");
	Menu(head);
}
void Alter(LinkList head)
{
     
	int loop=0;
	int n;
	char name[10];
	printf("请输入要查询联系人的姓名 [     ]\b\b\b\b\b\b");
	scanf("%s",name);
	printf("\n");
	LinkList rear=head->next; 
	while(rear)
	{
     
		if (strcmp(rear->data.name,name)==0)
			{
     
				printf("请输入要修改的内容:(1)编号 (2)姓名 (3)性别 (4)电话号码 (5)全部信息 [ ]\b\b");//printf("%s\t%s\t%s\t%s\n",rear->data.num,rear->data.name,rear->data.sex,rear->data.phone);
				scanf("%d",&n);
				printf("\n");
				switch(n)
				{
     
					case 1: printf("请输入修改后的编号:");scanf("%s",rear->data.num);break;
					case 2: printf("请输入修改后的姓名:");scanf("%s",rear->data.name);break;
					case 3: printf("请输入修改后的性别:");scanf("%s",rear->data.sex);break;
					case 4: printf("请输入修改后的电话号码");scanf("%s",rear->data.phone);break;
					case 5: printf("请输入要修改联系人的信息: \n\n编号	姓名	性别	电话号码:\n");
					scanf("%s",rear->data.num);
					scanf("%s",rear->data.name);
					scanf("%s",rear->data.sex);
					scanf("%s",rear->data.phone);break;
				}
				system("cls");
				loop=1;
			}	
		rear=rear->next;
	 }
	 if(loop==0)
	 {
     
	 	printf("无此联系人!!!\n\n返回菜单(1) or 重新输入(2)[  ]\b\b\b");
	 	scanf("%d",&n);
	 	printf("\n");
		switch(n)
		{
     
			case 1:system("cls");Menu(head);break;
			case 2:system("cls");Alter(head);break;
		}
	 }
	save(head);
	printf("\n修改成功!返回菜单\n");
	system("pause");
	Menu(head);
}
void Delete(LinkList head)
{
     
	LinkList rear=head;//用来找要删除节点的前一节点 
	LinkList p=rear->next;//用来找要删除节点
	char name[10];
	int Loop=0,n;
	printf("请输入要删除联系人的姓名:[    ]\b\b\b\b\b");
	scanf("%s",name);
	printf("\n");
	while(p)
	{
     
		if(strcmp(p->data.name,name)==0)
		{
     
			rear->next=p->next;
			free(p);
			save(head); 
			Loop=1;
		}
		rear=p;
		p=p->next;
	}
	if(Loop==1)
	{
     
		printf("\n删除联系人成功!返回菜单\n");
		system("pause");
		Menu(head); 
	 } 
	else
	{
     
		printf("无此联系人!!!\n\n返回菜单(1) or 重新输入(2)[  ]\b\b\b");
	 	scanf("%d",&n);
	 	printf("\n");
		switch(n)
		{
     
			case 1:system("cls");Menu(head);break;
			case 2:system("cls");Delete(head);break;
		}
	}
}
void Statis_sex(LinkList head)
{
     
	int i=0;//记录男性数目 
	int j=GetLength(head);//获取总记录数 
	LinkList rear=head->next;
	char sex[10]="man";
	while(rear)
	{
     
		if(strcmp(rear->data.sex,sex)==0)
			i++;
		rear=rear->next; 
	 } 
	 printf("\n通信录中男性有 %d 人,有女性 %d 人。\n",i,j-i);
}
void Quit()
{
     
	printf("\n\t                         ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★\n\n");
	puts("\n");
	puts("\t                             ┃                                               ┃");
	puts("\t                             ┃                                               ┃");
	puts("\t                             ┃     感谢访问通信录管理系统!欢迎下次再来!      ┃");
	puts("\t                             ┃                                               ┃");
	puts("\t                             ┃                                               ┃");
	puts("\t                             ┃                  制作人:追足梦幻                ┃");
	puts("\t                             ┃                          2020.7.3             ┃ ");
	puts("\n ");

}
void Menu(LinkList head)
{
     
	int n;
	int choice=0;
	do
	{
     
		system("cls");
		printf("\n");
		printf("                                              ---通讯录管理系统---\n");
		puts("\n");
		printf("                                             1/按姓名查询联系人信息\n");
		puts("\n");
		printf("                                             2/  新建联系人\n");
		puts("\n");
		printf("                                             3/修改联系人信息\n");
		puts("\n");
		printf("                                             4/ 删除联系人信息\n");
		puts("\n");
		printf("                                             5/显示所有联系人信息\n");
		puts("\n");
		printf("                                             6/     退出\n");
		puts("\n");
		printf("                                          请选择服务种类(1-6) : [ ]\b\b");
	    scanf("%d",&n);
	    if(n<1||n>6)
		{
     
		   system("cls");
		   printf("选择错误!  请重新选择!\n");
		   system("pause");
		   choice=1;
		}
		else
		{
     
			break;
		}
	}while(choice==1);

		switch(n)
		{
      
			case 1:system("cls");Find(head);break;//Find函数查询 
			case 2:system("cls");Add(head);break;//Add函数新建联系人 
			case 3:system("cls");Alter(head);break;//Alter修改联系人信息 
			case 4:system("cls");Delete(head);break;//Delete删除联系人信息 
			case 5:system("cls");List(head);break;//List显示所有信息 
			case 6:system("cls");Quit();break;//退出 
		}
}
int main()
{
     
	LinkList head=InitList();
	head=Create(head);
	printf("\n信息录入成功!");
	system("pause"); 
	Menu(head); 
 } 

三,设计报告

接下来是我课设报告中的设计部分内容

一、 引言(简要说明设计题目的目的、意义、内容、主要任务等)

目的:构建通讯录管理系统
意义:对于一个通信录来说,要管理联系人的信息,包括编号,姓名,性别,电话。开发其系统主要为了帮助用户提高通讯录有管理效率,节约资源,提高信息的精确度。
内容:九大模块((主函数main(),菜单函数Menu(),退出选单函数Quit(),创建数据函数Create(),增减数据函数Add(),查找函数Find(),修改函数Alter(),删除函数Delete(),显示所有记录函数List())加上四个辅助功能函数(初始化链表函数InitList(),保存函数save(),获取链表长度函数GetLength(),统计性别函数Statis_sex())。
主要任务:
1,打开文件读取通信录信息
2,通过链式存储接受文件储存信息
3,对文件信息进行修改
4,保存修改并将信息写回文件

二、 正文(课程设计的主要内容,包括实验与观测方法和结果、仪器设备、计算方法、编程原理、数据处理、设计说明与依据、加工整理和图表、形成的论点和导出的结论等。正文内容必须实事求是、客观真切、准确完备、合乎逻辑、层次分明、语言流畅、结构严谨,符合各学科、专业的有关要求。)

主要内容:首先定义结构体,定义主函数,定义链表初始化函数,用主函数调用链表初始化函数构建链表 head,接下来的所有操作基于链表head,调用Create()函数以将文件里面的数据写出并赋给链表,链表里面每个结点的属性为定义的结构体类型,然后调用Menu()函数以显示欢迎界面和菜单。
Menu函数通过switch条件语句调用各功能函数,选择1时,
1, 可按姓名查询联系人;
2, 新建联系人并保存到文件;
3, 可以修改联系人信息并保存,修改联系人信息有包括了对联系人编号,姓名,性别,电话号码的分别修改,也可以同时对编号,姓名,性别,电话号码修改;
4, 修改联系人信息;
5, 显示所有联系人信息并停机男女个数;
6, 可以调用fail函数以显示退出系统页面。

总流程图
数据结构课程设计-通讯录管理系统(C语言版)_第1张图片
每模块都需有每个函数功能介绍,截图,关键代码等

1, 定义结构体

typedef struct person{
     
	char num[10];//编号 
	char name[10];//姓名 
	char sex[10];//性别 
	char phone[10];//电话 
}personal;

typedef struct node
{
     
	person data;//数据域 
	struct node * next;//指针域 
}ListNode,* LinkList;

2, 链表初始化

LinkList InitList()
{
     
	LinkList head=(LinkList)malloc(sizeof(ListNode));//创立头结点
	if(head==NULL)
	{
     
		printf("空间分配无效!");		
		exit(-1);//退出程序
	}
	head->next=NULL;
	return head;
}
3,主函数
int main()
{
     
	LinkList head=InitList();
	head=Create(head);
	printf("\n信息录入成功!");
	system("pause"); 
	Menu(head); 
 }

首先初始化链表 head,然后或读取文件file.txt中的数据挂靠到链表 head=Create()

4, 读取文件数据到链表Create()
打开文件 file.txt FILE *fp= fopen(“file.txt”,“r”); 然后从头到尾处理文件将每一个联系人的数据写入结构体变量,并挂靠到链表中

while(fscanf(fp,"%s%s%s%s",LM.num,LM.name,LM.sex,LM.phone)!=EOF)//处理到文件尾 
{
       
       LinkList s=(LinkList)malloc(sizeof(ListNode));
       s->data=LM;
       s->next=NULL;
       rear->next=s;
       rear=s;
    }

fclose(fp); 记得一定要关闭文件
return head; 此时返回的链表就是一个满载数据的链表了,以后的操作都基于这条链表

5,菜单函数Menu()
关键代码: switch() 选择语句

6,按姓名查找 Find()
遍历链表知道找到要查询联系人姓名为止
关键代码:

LinkList rear=head->next; //跳过第一个节点,因为第一个节点没有存数据
	while(rear)//循环直到链表结束
	{
     
		if (strcmp(rear->data.name,name)==0) //字符串比较函数,如果与输入联系人姓名相同则打印
			{
     
				printf("编号	姓名	性别	电话 \n");
				printf("%s\t%s\t%s\t%s\n",rear->data.num,rear->data.name,rear->data.sex,rear->data.phone);
				Loop=1;
			}
		rear=rear->next;//循环进行下去的标志
	 }

7,新增加新的记录Add()
定义结构体变量LM person LM;
将要新建的联系人信息赋给 LM;
再用尾插法将LM添加到链表head
关键代码:

LinkList s=(LinkList)malloc(sizeof(ListNode));
		s->data=LM;
		s->next=NULL;
		while(p->next)
		{
     
			p=p->next;
		}//处理到最后防止产生野指针
		p->next=s;//插入s
		save(head);//记得保存修改

8,保存函数save
打开文件只允许写数据,文件从头处理到位,并将链表中的数据写入文件
关键代码:

LinkList rear;
	person LM;
	rear=head->next;//跳过头节点 
	FILE *fp;
	int i;
    if((fp=fopen("file.txt","wb"))==NULL)/*只打开或建立一个二进制文件,只允许写数据*/
	{
     
		printf("\n文件不存在!\n");
	}
	while(rear)//处理到文件尾 
    {
       
    	LM=rear->data;
    	fprintf(fp,"%s\t%s\t%s\t%s\n",LM.num,LM.name,LM.sex,LM.phone);
    	rear=rear->next;
}
fclose(fp);//处理完,一定要关闭文件

9,修改信息函数Alter()
遍历链表数据,查找输入的关键字(姓名),找到后锁定这一结点并通过一个switch语句选择要修改的信息(编号,姓名,性别,电话号码,全部信息),选择好后对应结点数据相应位置覆盖修改即可。
关键代码:

while(rear)
	{
     
		if (strcmp(rear->data.name,name)==0)
			{
     
				printf("请输入要修改的内容:(1)编号 (2)姓名 (3)性别 (4)电话号码 (5)全部信    息 [ ]\b\b");
				scanf("%d",&n);
				printf("\n");
				switch(n)
				{
     
					case 1: printf("请输入修改后的编号:");scanf("%s",rear->data.num);break;
					… …
					scanf("%s",rear->data.num);
                    … …
				}
			}	
		rear=rear->next;
	 }

修改完save()保存
10,删除联系人信息函数Delete()
删除节点图解:
数据结构课程设计-通讯录管理系统(C语言版)_第2张图片
遍历链表,寻找关键字(姓名),分别用两个指针(rear,p)指向关键字这一结点和它前一结点,
关键代码:

while(p)
	{
     
		if(strcmp(p->data.name,name)==0)
		{
     
			rear->next=p->next;
			free(p);//释放删除的结点
			save(head); 
			Loop=1;
		}
		rear=p;
		p=p->next;
	}

11,显示所有信息List()
从头到尾遍历链表,打印除头结点的数据域的数据即可。
关键代码:

LinkList p;
	p = head->next;
	{
     
		printf("\n通信录:\n\n");
		printf("编号	姓名	性别	电话 \n");
		while (p)  //循环将各个节点值输出
		{
     		
			printf("%s\t%s\t%s\t%s\n",p->data.num,p->data.name,p->data.sex,p->data.phone);//打印
			p = p->next;//此句放在打印后面,防止产生野指针 
		}
		Statis_sex(head);//显示性别人数

12,统计性别人数Statis_sex()
先计算出链表总长度 j,再以某一性别作为关键字遍历链表并计数统计这一性别的人数i,用j-i即是另一性别的人数。
关键代码;

int i=0;//记录男性数目 
	int j=GetLength(head);//获取总记录数 
	LinkList rear=head->next;
	char sex[10]="man";
	while(rear)
	{
     
		if(strcmp(rear->data.sex,sex)==0)
			i++;
		rear=rear->next; 
	 } 
	 printf("\n通信录中男性有 %d 人,有女性 %d 人。\n",i,j-i);

13, 获取链表长度GetLength()
从头到尾遍历链表并计数
关键代码:

{
     
	LinkList p=head->next;
	int i=0;
	while(p)
	{
     
		i++;
		p=p->next;

	}
	return i;
}//获取链表长度


关键步骤运行截图
数据结构课程设计-通讯录管理系统(C语言版)_第3张图片
数据结构课程设计-通讯录管理系统(C语言版)_第4张图片
数据结构课程设计-通讯录管理系统(C语言版)_第5张图片

数据结构课程设计-通讯录管理系统(C语言版)_第6张图片
数据结构课程设计-通讯录管理系统(C语言版)_第7张图片
数据结构课程设计-通讯录管理系统(C语言版)_第8张图片
数据结构课程设计-通讯录管理系统(C语言版)_第9张图片
数据结构课程设计-通讯录管理系统(C语言版)_第10张图片
数据结构课程设计-通讯录管理系统(C语言版)_第11张图片

三、结论(应当准确、完整、明确精练;也可以在结论或讨论中提出建议、设想、尚待解决问题等。
1、课程设计的特点
根据问题描述可知,需要解决问题并不复杂,整个问题只需要实现一个通讯录管理系统功能,那就是在这个系统中实现对通信录信息的插入、删除、查询、修改以及保存。但是,为了实现该功能,却需要优秀的算法和数据结构以保证实现的时间和空间效率。把联系人信息存储在一个单链表中,利用指针实现对联系人信息的各项基本操作。
2、存在的不足
虽然设计的程序完成了题目描述所需要实现的功能,但是仍然存在不尽人意的地方。那就是可以再排序上面多设计几个算法。实现多角度排序。
3、心得体会
经过这次数据结构课程设计,我们不仅及时巩固的了数据结构、算法、以及软件工程的知识,并对数据结构和算法的配合对于程序时间和空间性能的影响以及软件工程提供的开发流程和工具对于实现特定功能程序的重要意义。
当我们面对一个实际问题,应该迅速根据问题性质和特点抽象成特定的数据结构,当然每个问题都有可能能够抽象成多种数据结构,每种数据结构适应于不同的算法,例如,马踏棋盘问题就可以采用广度优先搜索或深度优先搜索来解决。因此此时就应该综合考虑这样的数据结构、算法以及它们的空间和时间效率,然后从中选择一个作为实现程序的基础。
此外,对程序的测试应该要仔细,根据模块的特点和测试阶段,采用各种软件测试方法对程序进行测试,确保各个模块的正确性和完整性,最后集成起来测试其是否正确和完整地实现了问题描述中要求的功能。

4、程序经验教训总结:
通过这个程序设计,我不仅提高了动手操作能力,对 C语言和数据结构有了更深的认识, 能够更好地运用 C语言进行编程设计,同时在思维、看待问题的全面性等方面也有了很大的提高。不过由于时间、经验不够、对语言的掌握程度不深等问题,在这个系统设计还存在一些问题,比如内存设计还不够完善,整个系统的流畅性等,希望可以在今后的设计上能够解决这些问题,做的更好。
四、参考文献
[1] 严蔚敏,吴伟民编著.《数据结构(C语言版)》.北京:清华大学出版社,1997.4. 18-39
[2] 菜鸟教程 网站https://www.runoob.com/
[3] CSDN 网站 https://www.csdn.net/

你可能感兴趣的:(数据结构,编程,数据结构,链表,编程语言)