当前位置: 首页 > news >正文

数据结构——基于单链表创建通讯录

1.  通讯录的功能

1. contach.c

1. 初始化通讯录

2. 添加通讯录数据

3. 删除通讯录数据

4. 展示通讯录数据

5. 查找通讯录数据

6. 修改通讯录数据

7. 销毁通讯录数据

2. SList.c

1. 尾插

2. 删除指定节点

3. 销毁链表

2. 通讯录的定义

1. contach.h

创建一个结构体,存储联系人数据

//前置声明
typedef struct SListNode contact;

//用户数据
typedef struct PersonInfo
{
    char name[NAME_MAX];
    char sex[SEX_MAX];
    int age;
    char tel[TEL_MAX];
    char addr[ADDR_MAX];
}PeoInfo;

2. SList.h

创建一个结构体包含两个成员,一个成员存储联系人数据,一个成员存储下一个结点的地址(当下一个节点为空时保存的地址为NULL)

typedef PeoInfo SLTDataType;
struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
};

3. 通讯录功能实现

1. contach.c

 查找通讯录中名字相同的联系人

contact* FindName(contact* con, char name[]) {
	assert(con);
	while (con) {
		if (strcmp(con->data.name, name) == 0) {
			return con;
		}
		con = con->next;
	}
	return NULL;
}

1. 初始化通讯录

//将contact.text文件中的数据导入到通讯录链表中
void LoadContact(contact** con) {
	FILE* pf = fopen("contact.txt", "rb");//打开一个存放通讯录的二进制文件,只读
	if (pf == NULL) {
		perror("文件打开失败");
		return;
	}
	PeoInfo ps;
	//循环读取文件数据
	while (fread(&ps, sizeof(ps), 1, pf)) {
		SLTPushBack(con, ps);
	}
	printf("历史数据导入通讯录成功\n");
	fclose(pf);//关闭文件
}
//初始化通讯录
void InitContact(contact** con) {
	LoadContact(con);
	printf("通讯录初始化完成\n");
}

2. 添加通讯录数据

void AddContact(contact** con) {
	PeoInfo ps;
	printf("请输入姓名:");
	scanf("%s", ps.name);
	printf("请输入性别:");
	scanf("%s", ps.sex);
	printf("请输入年龄:");
	scanf("%d", &ps.age);
	printf("请输入电话:");
	scanf("%s", ps.tel);
	printf("请输入地址:");
	scanf("%s", ps.addr);
	SLTPushBack(con, ps);//因为SLTPushBack的第一个参数是 contact** con
}

3. 删除通讯录数据

void DelContact(contact** con) {
	char name[NAME_MAX];
	printf("输入要删除的姓名:");
	scanf("%s", name);
	contact* pos = FindName(*con, name);
	if (pos) {
		SLTErase(con, pos);
		printf("删除成功\n");
	}
	else {
		printf("该联系人不存在,无法删除\n");
	}
}

4. 展示通讯录数据

void ShowContact(contact* con) {
	while (con) {
		printf("姓名:%s  性别:%s  年龄:%d  电话:%s  地址:%s\n",
			con->data.name,
			con->data.sex,
			con->data.age,
			con->data.tel,
			con->data.addr);
		con = con->next;
	}
}

5. 查找通讯录数据

void FindContact(contact* con) {
	char name[NAME_MAX];
	printf("输入要查找的姓名:");
	scanf("%s", name);
	contact* pos=FindName(con, name);
	if (pos) {
		printf("找到了\n");
		printf("姓名:%s  性别:%s  年龄:%d  电话:%s  地址:%s\n",
			pos->data.name,
			pos->data.sex,
			pos->data.age,
			pos->data.tel,
			pos->data.addr);
	}
	else {
		printf("该联系人不存在\n");
	}
}

6. 修改通讯录数据

void ModifyContact(contact** con) {
	char name[NAME_MAX];
	printf("请输入要修改的姓名:");
	scanf("%s", name);
	contact* pos = FindName(*con, name);
	if (pos) {
		printf("请输入修改的姓名:");
		scanf("%s", pos->data.name);
		printf("请输入修改的性别:");
		scanf("%s", pos->data.sex);
		printf("请输入修改的年龄:");
		scanf("%d", &pos->data.age);
		printf("请输入修改的电话:");
		scanf("%s", pos->data.tel);
		printf("请输入修改的地址:");
		scanf("%s", pos->data.addr);
	}
	else {
		printf("该联系人不存在,无法修改\n");
	}
}

7. 销毁通讯录数据

void SaveContact(contact* con) {
	assert(con);
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL) {
		perror("fopen fail\n");
		return;
	}
	while (con) {
		fwrite(&(con->data), sizeof(con->data), 1, pf);
		con = con->next;
	}
	printf("通讯录保存成功\n");
	fclose(pf);
}
//销毁通讯录数据
void DestroyContact(contact** con) {
	SaveContact(*con);
	//销毁通讯录数据
	SListDesTroy(con);
}

2. SList.c

创建节点

SLTNode* BuyNode(SLTDataType x) {
    SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
    //如果创建失败
    if (node == NULL) {
        perror("malloc fail!\n");
        exit(1);
    }
    node->data = x;
    node->next = NULL;
    return node;//返回该节点
}

1. 尾插

//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
    assert(pphead);//pphead不为空
    SLTNode* node = BuyNode(x);//创建新节点
    //如果链表为空
    if (*pphead == NULL) {
        *pphead = node;//新节点为头节点
        return;
    }
    //找尾
    SLTNode* cur = *pphead;
    while (cur->next) {
        cur = cur->next;
    }
    cur->next = node;//将新节点进行尾插
}

2. 删除指定节点

 //删除pos
void SLTErase(SLTNode** pphead, SLTNode* pos) {
    assert(pphead);
    assert(pos);//检测pos节点不为空,如果pos节点不为空,那么该链表也不为空
    //如果pos==头节点
    if (*pphead == pos) {
        //        SLTNode *del = *pphead;
        //        *pphead = (*pphead)->next;
        //        free(del);
        //        del = NULL;
        SLTPopFront(pphead);//头删
        return;
    }
    //找pos的前一个节点
    SLTNode* prev = *pphead;
    while (prev->next) {
        if (prev->next == pos) {
            break;
        }
        prev = prev->next;
    }
    prev->next = pos->next;//删除pos节点
    free(pos);//释放pos节点
    //    pos = NULL;//没有存在的必要
}

3. 销毁链表

void SListDesTroy(SLTNode** pphead) {
    SLTNode* pointer = NULL;
    while (*pphead) {
        pointer = *pphead;
        *pphead = (*pphead)->next;
        free(pointer);
        pointer = NULL;
    }
}

4. 完整代码展示

1. contach.h

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

//前置声明
typedef struct SListNode contact;

//用户数据
typedef struct PersonInfo
{
    char name[NAME_MAX];
    char sex[SEX_MAX];
    int age;
    char tel[TEL_MAX];
    char addr[ADDR_MAX];
}PeoInfo;

//初始化通讯录
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);

2. SList.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "contach.h"
typedef PeoInfo SLTDataType;
struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
};
typedef struct SListNode SLTNode;
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

3. contach.c

#include "contach.h"
#include "SList.h"
//将contact.text文件中的数据导入到通讯录链表中
void LoadContact(contact** con) {
	FILE* pf = fopen("contact.txt", "rb");//打开一个存放通讯录的二进制文件,只读
	if (pf == NULL) {
		perror("文件打开失败");
		return;
	}
	PeoInfo ps;
	//循环读取文件数据
	while (fread(&ps, sizeof(ps), 1, pf)) {
		SLTPushBack(con, ps);
	}
	printf("历史数据导入通讯录成功\n");
	fclose(pf);//关闭文件
}
//初始化通讯录
void InitContact(contact** con) {
	LoadContact(con);
	printf("通讯录初始化完成\n");
}
//展示通讯录数据
void ShowContact(contact* con) {
	while (con) {
		printf("姓名:%s  性别:%s  年龄:%d  电话:%s  地址:%s\n",
			con->data.name,
			con->data.sex,
			con->data.age,
			con->data.tel,
			con->data.addr);
		con = con->next;
	}
}
//添加通讯录数据(尾插)
void AddContact(contact** con) {
	PeoInfo ps;
	printf("请输入姓名:");
	scanf("%s", ps.name);
	printf("请输入性别:");
	scanf("%s", ps.sex);
	printf("请输入年龄:");
	scanf("%d", &ps.age);
	printf("请输入电话:");
	scanf("%s", ps.tel);
	printf("请输入地址:");
	scanf("%s", ps.addr);
	SLTPushBack(con, ps);//因为SLTPushBack的第一个参数是 contact** con
}

//查找通讯录中名字相同的数据
contact* FindName(contact* con, char name[]) {
	assert(con);
	while (con) {
		if (strcmp(con->data.name, name) == 0) {
			return con;
		}
		con = con->next;
	}
	return NULL;
}
//删除通讯录数据
void DelContact(contact** con) {
	char name[NAME_MAX];
	printf("输入要删除的姓名:");
	scanf("%s", name);
	contact* pos = FindName(*con, name);
	if (pos) {
		SLTErase(con, pos);
		printf("删除成功\n");
	}
	else {
		printf("该联系人不存在,无法删除\n");
	}
}
//查找通讯录数据
void FindContact(contact* con) {
	char name[NAME_MAX];
	printf("输入要查找的姓名:");
	scanf("%s", name);
	contact* pos=FindName(con, name);
	if (pos) {
		printf("找到了\n");
		printf("姓名:%s  性别:%s  年龄:%d  电话:%s  地址:%s\n",
			pos->data.name,
			pos->data.sex,
			pos->data.age,
			pos->data.tel,
			pos->data.addr);
	}
	else {
		printf("该联系人不存在\n");
	}
}
//修改通讯录数据
void ModifyContact(contact** con) {
	char name[NAME_MAX];
	printf("请输入要修改的姓名:");
	scanf("%s", name);
	contact* pos = FindName(*con, name);
	if (pos) {
		printf("请输入修改的姓名:");
		scanf("%s", pos->data.name);
		printf("请输入修改的性别:");
		scanf("%s", pos->data.sex);
		printf("请输入修改的年龄:");
		scanf("%d", &pos->data.age);
		printf("请输入修改的电话:");
		scanf("%s", pos->data.tel);
		printf("请输入修改的地址:");
		scanf("%s", pos->data.addr);
	}
	else {
		printf("该联系人不存在,无法修改\n");
	}
}
//将通讯录保存到contact.txt文件中
void SaveContact(contact* con) {
	assert(con);
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL) {
		perror("fopen fail\n");
		return;
	}
	while (con) {
		fwrite(&(con->data), sizeof(con->data), 1, pf);
		con = con->next;
	}
	printf("通讯录保存成功\n");
	fclose(pf);
}
//销毁通讯录数据
void DestroyContact(contact** con) {
	SaveContact(*con);
	//销毁通讯录数据
	SListDesTroy(con);
}

4. SList.c

//创建节点
SLTNode* BuyNode(SLTDataType x) {
    SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
    //如果创建失败
    if (node == NULL) {
        perror("malloc fail!\n");
        exit(1);
    }
    node->data = x;
    node->next = NULL;
    return node;//返回该节点
}
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
    assert(pphead);//pphead不为空
    SLTNode* node = BuyNode(x);//创建新节点
    //如果链表为空
    if (*pphead == NULL) {
        *pphead = node;//新节点为头节点
        return;
    }
    //找尾
    SLTNode* cur = *pphead;
    while (cur->next) {
        cur = cur->next;
    }
    cur->next = node;//将新节点进行尾插
}
// 删除pos
void SLTErase(SLTNode** pphead, SLTNode* pos) {
    assert(pphead);
    assert(pos);//检测pos节点不为空,如果pos节点不为空,那么该链表也不为空
    //如果pos==头节点
    if (*pphead == pos) {
        //        SLTNode *del = *pphead;
        //        *pphead = (*pphead)->next;
        //        free(del);
        //        del = NULL;
        SLTPopFront(pphead);//头删
        return;
    }
    //找pos的前一个节点
    SLTNode* prev = *pphead;
    while (prev->next) {
        if (prev->next == pos) {
            break;
        }
        prev = prev->next;
    }
    prev->next = pos->next;//删除pos节点
    free(pos);//释放pos节点
    //    pos = NULL;//没有存在的必要
}
//销毁链表
void SListDesTroy(SLTNode** pphead) {
    SLTNode* pointer = NULL;
    while (*pphead) {
        pointer = *pphead;
        *pphead = (*pphead)->next;
        free(pointer);
        pointer = NULL;
    }
}

5. text.c

#include "contach.h"
#include "SList.h"
void Realize(void) {
	contact* con = NULL;
	//初始化通讯录
	InitContact(con);
	//添加通讯录数据
	AddContact(&con);
	AddContact(&con);
	AddContact(&con);
	//删除通讯录数据
	DelContact(&con);
	//查找通讯录数据
	FindContact(con);
	//修改通讯录数据
	ModifyContact(&con);
	//展示通讯录数据
	ShowContact(con);
	//销毁通讯录数据
	DestroyContact(&con);
}
int main() {
	Realize();
	return 0;
}

相关文章:

  • LangChain教程 - RAG - PDF问答
  • HarmonyOS+Django实现图片上传
  • AVFormatContext
  • Node.js v16 版本安装
  • 排序(数据结构篇)
  • YOLOv12 ——基于卷积神经网络的快速推理速度与注意力机制带来的增强性能结合
  • 百度觉醒,李彦宏渴望光荣
  • 浅析 Redis 分片集群 Cluster 原理、手动搭建、动态伸缩集群、故障转移
  • 《Spring Boot + MySQL高性能应用实战:性能优化技巧与最佳实践》
  • CMake小结2(PICO为例)
  • 【目标检测旋转框xml2txt】rolabelimg标注的xml格式label转YOLO格式txt文件
  • 【Java项目】基于Spring Boot的旅游管理系统
  • Blueprint —— Events
  • vue3-07模拟vue3的响应式原理Proxy (代理对象)与Reflect (反射对象)
  • NNP_test_cpp
  • 深度强化学习落地调参技巧
  • 企业之IT安全管控概览和实践案例
  • Docker下ARM64架构的源码编译Qt5.15.1,并移植到开发板上
  • 新版本的idea用不习惯,怎么还原为之前版本的UI界面?idea界面还原,idea新版本ui设置
  • 一文了解Java中的虚拟线程新特性
  • 4月新增社融1.16万亿,还原地方债务置换影响后信贷增速超过8%
  • 加强战略矿产出口全链条管控将重点开展哪些工作?商务部答问
  • 李公明 | 一周画记:印巴交火会否升级为第四次印巴战争?
  • 消费维权周报|上周涉手机投诉较多,涉拍照模糊、屏幕漏液等
  • 湖北石首市委副书记、市长付勇接受审查调查
  • 人民日报读者点题·共同关注:今天我们为什么还需要图书馆?