数据结构——基于单链表实现通讯管理系统

一、前言

这个通讯录是基于单链表实现的,关于单链表,之前已经做过完整的实现方法——数据结构——单链表(C语言版)
用单链表实现的通讯录其实和用顺序表实现的通讯录类似,可以参考该文章——基于动态顺序表的应用——通讯录


完成该通讯录需要引进经过修改后的单链表的文件

SList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include  "Contact.h"

typedef PeoInfo SLTDateType;

typedef struct SListNode
{
	SLTDateType date;
	struct SListNode* next;
}SLTNode;

//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x);

//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x);

//尾删
void SLTPopBack(SLTNode** pphead);

//头删
void SLTPopFront(SLTNode** pphead);

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x);

//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);

//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos);

//销毁链表
void SListDesTroy(SLTNode** pphead);

SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"

//申请新的结点
SLTNode* SLTBuyNode(SLTDateType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		printf("malloc fail!");
		exit(1);
	}
	newnode->date = x;
	newnode->next = NULL;
	return newnode;
}

//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	//空链表 和 非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* ptail = *pphead;
		while (ptail->next)
		{
			ptail = ptail->next;
		}
		ptail->next = newnode;
	}
}

//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//尾删
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead && *pphead);
	//只有一个结点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//多个结点
	else
	{
		SLTNode* prev = *pphead;
		SLTNode* ptail = *pphead;

		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		free(ptail);
		ptail = NULL;
		prev->next = NULL;
	}
}

//头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	assert(pphead && *pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* newnode = SLTBuyNode(x);
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = newnode;
		newnode->next = pos;
	}
	
}

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
	
}

//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next);
	SLTNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}

//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pcur = *pphead;
	
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

二、通讯录的实现

通讯录项目

创建一个通讯录项目,包含以下文件:

在这里插入图片描述

Contact.h 通讯录的头文件,包含通讯录的声明以及相关函数的声明
Contact.c 通讯录函数的具体实现方法
contact.txt 保存通讯录中的数据

SList.h 单链表的声明
SList.c 单链表函数的声明

test.c 测试代码,也可以当菜单

Contact.h

#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100

//联系人的数据
//姓名 性别 年龄 电话 地址
typedef struct PersonInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

//前置声明
typedef struct SListNode contact;

//初始化通讯录
void InitContact(contact** con);

//添加通讯录数据
void AddContact(contact** con);

//删除通讯录数据
void DelContact(contact** con);

//展示通讯录数据
void ShowContact(contact* con);

//查找通讯录数据
void FindContact(contact* con);

//修改通讯录数据
void ModifyContact(contact** con);

//销毁通讯录数据
void DestroyContact(contact** con);

载入数据

//载入数据
void LoadContact(contact** con)
{
	FILE* pf = fopen("contact.txt", "r");
	//判断读取是否成功
	if (pf == NULL)
	{
		perror("fopen fail!");
		return;
	}
	//循环读取数据
	PeoInfo info;
	while (fread(&info, sizeof(PeoInfo), 1, pf))
	{
		SLTPushBack(con, info);
	}
	printf("历史数据导入通讯录成功!\n");
}

初始化通讯录

//初始化通讯录
void InitContact(contact** con)
{
	LoadContact(con);
}

添加通讯录数据

// 添加通讯录数据
void AddContact(contact** con)
{
	PeoInfo info;
	printf("请输入联系人的姓名:\n");
	scanf("%s", info.name);

	printf("请输入联系人的性别:\n");
	scanf("%s", info.sex);

	printf("请输入联系人的年龄:\n");
	scanf("%d", &info.age);

	printf("请输入联系人的电话:\n");
	scanf("%s", info.tel);

	printf("请输入联系人的地址:\n");
	scanf("%s", info.addr);

	SLTPushBack(con, info);
}

通过姓名查找联系人

//通过姓名查找联系人
contact* FindByName(contact* con, char name[])
{
	contact* pcur = con;
	while (pcur)
	{
		if (strcmp(pcur->date.name, name) == 0)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

删除通讯录数据

//删除通讯录数据
void DelContact(contact** con)
{
	char name[NAME_MAX];
	printf("请输入要删除的联系人的姓名->");
	scanf("%s", name);
	contact* pos = FindByName(*con, name);
	if (pos != NULL)
	{
		SLTErase(con, pos);
		printf("删除成功!\n");
	}
	else
	{
		printf("删除失败!没有该联系人!\n");
	}
}

展示通讯录数据

//展示通讯录数据
void ShowContact(contact* con)
{
	printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");
	contact* pcur = con;
	while (pcur)
	{
		printf("%6s %6s %6d %6s %6s\n",
			pcur->date.name,
			pcur->date.sex,
			pcur->date.age,
			pcur->date.tel,
			pcur->date.addr);
		pcur = pcur->next;
	}
}

查找通讯录数据

//查找通讯录数据
void FindContact(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人的姓名->");
	scanf("%s", name);
	contact* pos = FindByName(con, name);
	if (pos == NULL)
	{
		printf("没有该联系人!\n");
	}
	else
	{
		printf("找到了!该联系人的信息如下:\n");
		printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%6s %6s %6d %6s %6s\n",
			pos->date.name,
			pos->date.sex,
			pos->date.age,
			pos->date.tel,
			pos->date.addr);
	}
}

修改通讯录数据

//修改通讯录数据
void ModifyContact(contact** con)
{
	char name[NAME_MAX];
	printf("请输入要修改的联系人的姓名->");
	scanf("%s", name);
	contact* pos = FindByName(*con, name);
	if (pos == NULL)
	{
		printf("没有该联系人!\n");
	}
	else
	{
		printf("开始修改!\n");
		printf("联系人的新姓名为:\n");
		scanf("%s", pos->date.name);

		printf("联系人的新性别为:\n");
		scanf("%s", pos->date.sex);

		printf("联系人的新年龄为:\n");
		scanf("%d", &pos->date.age);

		printf("联系人的新电话为:\n");
		scanf("%s", pos->date.tel);

		printf("联系人的新地址为:\n");
		scanf("%s", pos->date.addr);

		printf("修改成功!\n");
	}
}

保存通讯录

//保存通讯录
void SaveContact(contact* con)
{
	FILE* pf = fopen("contact.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail!");
		return;
	}
	//将通讯录数据写入文件
	contact* pcur = con;
	while (pcur)
	{
		fwrite(&(pcur->date), sizeof(pcur->date), 1, pf);
		pcur = pcur->next;
	}
	printf("通讯录保存成功!\n");
}

销毁通讯录数据

//销毁通讯录数据
void DestroyContact(contact** con)
{
	//在销毁通讯录之前,保存数据
	SaveContact(*con);
	SListDesTroy(con);
}

三、所有源代码

Contact.h

#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100

//联系人的数据
//姓名 性别 年龄 电话 地址
typedef struct PersonInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

//前置声明
typedef struct SListNode contact;

//初始化通讯录
void InitContact(contact** con);

//添加通讯录数据
void AddContact(contact** con);

//删除通讯录数据
void DelContact(contact** con);

//展示通讯录数据
void ShowContact(contact* con);

//查找通讯录数据
void FindContact(contact* con);

//修改通讯录数据
void ModifyContact(contact** con);

//销毁通讯录数据
void DestroyContact(contact** con);

Contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
#include "SList.h"

//载入数据
void LoadContact(contact** con)
{
	FILE* pf = fopen("contact.txt", "r");
	//判断读取是否成功
	if (pf == NULL)
	{
		perror("fopen fail!");
		return;
	}
	//循环读取数据
	PeoInfo info;
	while (fread(&info, sizeof(PeoInfo), 1, pf))
	{
		SLTPushBack(con, info);
	}
	printf("历史数据导入通讯录成功!\n");
}

//初始化通讯录
void InitContact(contact** con)
{
	LoadContact(con);
}

// 添加通讯录数据
void AddContact(contact** con)
{
	PeoInfo info;
	printf("请输入联系人的姓名:\n");
	scanf("%s", info.name);

	printf("请输入联系人的性别:\n");
	scanf("%s", info.sex);

	printf("请输入联系人的年龄:\n");
	scanf("%d", &info.age);

	printf("请输入联系人的电话:\n");
	scanf("%s", info.tel);

	printf("请输入联系人的地址:\n");
	scanf("%s", info.addr);

	SLTPushBack(con, info);
}

//通过姓名查找联系人
contact* FindByName(contact* con, char name[])
{
	contact* pcur = con;
	while (pcur)
	{
		if (strcmp(pcur->date.name, name) == 0)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

//删除通讯录数据
void DelContact(contact** con)
{
	char name[NAME_MAX];
	printf("请输入要删除的联系人的姓名->");
	scanf("%s", name);
	contact* pos = FindByName(*con, name);
	if (pos != NULL)
	{
		SLTErase(con, pos);
		printf("删除成功!\n");
	}
	else
	{
		printf("删除失败!没有该联系人!\n");
	}
}

//展示通讯录数据
void ShowContact(contact* con)
{
	printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");
	contact* pcur = con;
	while (pcur)
	{
		printf("%6s %6s %6d %6s %6s\n",
			pcur->date.name,
			pcur->date.sex,
			pcur->date.age,
			pcur->date.tel,
			pcur->date.addr);
		pcur = pcur->next;
	}
}

//查找通讯录数据
void FindContact(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人的姓名->");
	scanf("%s", name);
	contact* pos = FindByName(con, name);
	if (pos == NULL)
	{
		printf("没有该联系人!\n");
	}
	else
	{
		printf("找到了!该联系人的信息如下:\n");
		printf("%6s %6s %6s %6s %6s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%6s %6s %6d %6s %6s\n",
			pos->date.name,
			pos->date.sex,
			pos->date.age,
			pos->date.tel,
			pos->date.addr);
	}
}

//修改通讯录数据
void ModifyContact(contact** con)
{
	char name[NAME_MAX];
	printf("请输入要修改的联系人的姓名->");
	scanf("%s", name);
	contact* pos = FindByName(*con, name);
	if (pos == NULL)
	{
		printf("没有该联系人!\n");
	}
	else
	{
		printf("开始修改!\n");
		printf("联系人的新姓名为:\n");
		scanf("%s", pos->date.name);

		printf("联系人的新性别为:\n");
		scanf("%s", pos->date.sex);

		printf("联系人的新年龄为:\n");
		scanf("%d", &pos->date.age);

		printf("联系人的新电话为:\n");
		scanf("%s", pos->date.tel);

		printf("联系人的新地址为:\n");
		scanf("%s", pos->date.addr);

		printf("修改成功!\n");
	}
}

//保存通讯录
void SaveContact(contact* con)
{
	FILE* pf = fopen("contact.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail!");
		return;
	}
	//将通讯录数据写入文件
	contact* pcur = con;
	while (pcur)
	{
		fwrite(&(pcur->date), sizeof(pcur->date), 1, pf);
		pcur = pcur->next;
	}
	printf("通讯录保存成功!\n");
}

//销毁通讯录数据
void DestroyContact(contact** con)
{
	//在销毁通讯录之前,保存数据
	SaveContact(*con);
	SListDesTroy(con);
}

SList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include  "Contact.h"

typedef PeoInfo SLTDateType;

typedef struct SListNode
{
	SLTDateType date;
	struct SListNode* next;
}SLTNode;

//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x);

//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x);

//尾删
void SLTPopBack(SLTNode** pphead);

//头删
void SLTPopFront(SLTNode** pphead);

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x);

//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);

//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos);

//销毁链表
void SListDesTroy(SLTNode** pphead);

SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"



//申请新的结点
SLTNode* SLTBuyNode(SLTDateType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		printf("malloc fail!");
		exit(1);
	}
	newnode->date = x;
	newnode->next = NULL;
	return newnode;
}

//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	//空链表 和 非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* ptail = *pphead;
		while (ptail->next)
		{
			ptail = ptail->next;
		}
		ptail->next = newnode;
	}
}

//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//尾删
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead && *pphead);
	//只有一个结点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//多个结点
	else
	{
		SLTNode* prev = *pphead;
		SLTNode* ptail = *pphead;

		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		free(ptail);
		ptail = NULL;
		prev->next = NULL;
	}
}

//头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	assert(pphead && *pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* newnode = SLTBuyNode(x);
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = newnode;
		newnode->next = pos;
	}
	
}

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
	
}

//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next);
	SLTNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}

//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pcur = *pphead;
	
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
//测试代码——菜单
void menu()
{
	printf("****************通讯录*******************\n");
	printf("******1.添加联系人    2.删除联系人*******\n");
	printf("******3.修改联系人    4.查找联系人*******\n");
	printf("******5.展示联系人    0. 退出************\n");
	printf("*****************************************\n");
}

int main()
{
	int input = 0;
	contact* con = NULL;
	//初始化
	InitContact(&con);
	do
	{
		menu();
		printf("选择你的操作->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			FindContact(con);
			break;
		case 5:
			ShowContact(con);
			break;
		case 0:
			printf("退出通讯录...\n");
			break;
		default:
			printf("输入错误!请重新输入!\n");
			break;
		}
	} while (input != 0);
	//销毁通讯录;
	DestroyContact(&con);
	return 0;
}

相关推荐

  1. 数据结构实现通讯录

    2024-04-13 23:44:04       31 阅读
  2. 数据结构4:基于通讯录项目

    2024-04-13 23:44:04       36 阅读
  3. 数据结构】利用实现通讯录

    2024-04-13 23:44:04       21 阅读
  4. 基于实现通讯录项目

    2024-04-13 23:44:04       62 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-13 23:44:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-13 23:44:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-13 23:44:04       82 阅读
  4. Python语言-面向对象

    2024-04-13 23:44:04       91 阅读

热门阅读

  1. 4月12日,每日信息差

    2024-04-13 23:44:04       30 阅读
  2. C++笔记打卡第11天(运算符重载、继承)

    2024-04-13 23:44:04       41 阅读
  3. 微信小程序常见面试题13道

    2024-04-13 23:44:04       33 阅读
  4. 有源与无源系统:Active Systems and Passive Systems

    2024-04-13 23:44:04       39 阅读
  5. R-tree总结

    2024-04-13 23:44:04       34 阅读
  6. 【并发】面试题汇总

    2024-04-13 23:44:04       37 阅读
  7. 面试题讲解

    2024-04-13 23:44:04       32 阅读
  8. R-tree总结

    2024-04-13 23:44:04       33 阅读
  9. 安全地创建一个临时文件 - mkstemp

    2024-04-13 23:44:04       36 阅读
  10. 游戏&软件测试流程

    2024-04-13 23:44:04       38 阅读
  11. springboot+vue2+mybatisplus实现文件上传

    2024-04-13 23:44:04       29 阅读
  12. mysql 配置说明

    2024-04-13 23:44:04       40 阅读
  13. 【Vue】$emits和props

    2024-04-13 23:44:04       33 阅读