【数据结构|C语言版】单链表应用

  • 前言
  • 1. 基于单链表实现通讯录
    • 1.1 知识要求
    • 1.2 功能要求
  • 2. 代码总结
    • 2.1 SeqList.h
    • 2.2 SeqList.c
    • 2.3 Contact.h
    • 2.4 Contact.c
    • 2.5 test.c
  • 后言


在这里插入图片描述

上期回顾:【数据结构|C语言版】单链表

前言

各位小伙伴大家好!上期小编讲解了单链表相关知识,在此基础上,我们来学习一下单链表的应用。
在这里插入图片描述

1. 基于单链表实现通讯录

1.1 知识要求

C语言基础要求:结构体、动态内存管理、单链表、文件操作

1.2 功能要求

① 至少能够存储100个人的通讯信息
② 能够保存用户信息:名字、性别、年龄、电话、地址等
③ 增加联系人信息
④ 删除指定联系人
⑤ 查找制定联系人
⑥修改指定联系人
⑦ 显示联系人信息

2. 代码总结

2.1 SeqList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include"Contact.h"//定义链表的结构
//typedef int SLDataType
typedef struct ContactInfo SLDataType;   //更改SLDataType的类型typedef struct SListNode
{SLDataType data;	//保存的数据struct SListNode* next;		//指针变量存放下一个节点的地址
}SLNode;//1 打印链表
void SLPrint(SLNode* phead);//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x);
//3 头插
void SLPushFront(SLNode** pphead, SLDataType x);//4 尾删
void SLPopBack(SLNode** pphead);//5 头删
void SLPopFront(SLNode** pphead);//SLFind()找到要查找数据的下标
//找节点的函数这里传一级实际上就可以了,因为不改变头结点
//但是这里要写二级指针,因为要保持接口一致性
//缺点:这个函数有一定的局限性,他找到数据x的下标是第一次出现的x的下标后,不会找后续的x的下标
SLNode* SLFind(SLNode** pphead, SLDataType x);//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x);//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x);//8 删除pos节点
void  SLErase(SLNode** pphead, SLNode* pos);//9 删除pos后的节点
void SLEraseAfter(SLNode* pos);//10 销毁链表
void SLDestory(SLNode** pphead);

2.2 SeqList.c

#include"SList_copy.h"//1 创建新的节点的函数
SLNode* SLBuyNode(SLDataType x)
{SLNode* node = (SLNode*)malloc(sizeof(SLNode));node->data = x;node->next = NULL;return node;
}//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x)	//保存第一个节点的指针的地址
{assert(pphead);//创建一个节点SLNode* node = SLBuyNode(x);if (*pphead == NULL){*pphead = node;return;}//链表不为空,找尾SLNode* pcur = *pphead;while (pcur->next)//相当于pcur->next!=NULL{pcur = pcur->next;}pcur->next = node;
}//3 头插
void SLPushFront(SLNode** pphead, SLDataType x)
{assert(pphead);SLNode* node = SLBuyNode(x);//新结点跟头结点连接起来node->next = *pphead;//让新节点成为头结点*pphead = node;
}//4 尾删
void SLPopBack(SLNode** pphead)
{assert(pphead);assert(*pphead);	//第一个节点不能为空//判断只有一个结点的情况if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}//找到尾节点和尾节点的前一个节点SLNode* pre = NULL;SLNode* ptail = *pphead;while (ptail->next){pre = ptail;ptail = ptail->next;}//pre的next指针不指向ptail,而是指向ptail的下一个节点//pre->next = NULL;pre->next = ptail->next;//因为在SLPrint(SLNode* phead)函数中有判断节点是否为空while (pcur),所以置空free(ptail);ptail = NULL;}//5 头插
void SLPopFront(SLNode** pphead)
{assert(pphead);assert(*pphead);	//第一个节点不能为空SLNode* del = *pphead;*pphead = (*pphead)->next;free(del);del = NULL;
}//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{assert(pphead);assert(pos);	//pos不能为空assert(*pphead);  //NULL前插入数据是荒谬的,所以assert第一个节点SLNode* node = SLBuyNode(x);//当只有一个结点(pos就是第一个节点)//if (((*pphead)->next) == NULL||pos==*pphead),可以简化成以下代码if (pos == *pphead) {node->next = *pphead;*pphead = node;return;}//找到pos的前一个节点SLNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}//处理pre node pos的位置node->next = pos;pre->next = node;
}//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x)
{assert(pos);SLNode* node = SLBuyNode(x);node->next = pos->next;pos->next = node;
}//8 删除pos节点
void SLErase(SLNode** pphead, SLNode* pos)
{assert(*pphead);assert(pphead);assert(pos);//pos是头结点if (pos == *pphead){*pphead = (*pphead)->next;free(pos);return;}//pos不是头结点,找pos的前一个节点SLNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}pre->next = pos->next;free(pos);pos = NULL;   //代码规范
}//9 删除pos后的节点
void SLEraseAfter(SLNode* pos)
{//删除pos之后的节点也不能空assert(pos && pos->next);SLNode* del = pos->next;pos->next = del->next;free(del);
}void SLDestory(SLNode** pphead)
{assert(pphead);SLNode* pcur = *pphead;while (pcur){SLNode* next = pcur->next;free(pcur);pcur = next;}//头结点记得置空*pphead = NULL;
}

2.3 Contact.h

#pragma once
//创建保存联系人数据的结构
#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50typedef struct ContactInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}ConInfo;
//前置声明
typedef struct SListNode contact;//1.打开通讯录
void ContactInit(contact** pcon);//2.保存数据后销毁通讯录
void ContactDestory(contact** pcon);//3.添加联系人
void ContactAdd(contact** pcon);//4.删除联系人
void ContactDel(contact** pcon);//5.修改联系人
void ContactModify(contact* con);//6.查找联系人
void ContactFind(contact* pcon);//7.查看通讯录
void ContactShow(contact* pcon);

2.4 Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SList_copy.h"//1.打开通讯录
void ContactInit(contact** pcon)
{FILE* pf = fopen("Contact_Info.txt", "rb");if (pf == NULL){perror("fopen error.\n");  //主动报错,打开失败return;}ConInfo info;//回顾一下fread //size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );//从流中读取一个由count元素组成的数组,每个元素的大小为size字节,并将它们存储在ptr指定的内存块中。//流的位置指示器按读取的总字节数前进。//如果成功读取的总字节数为(size * count)while (fread(&info, sizeof(info), 1, pf)){SLPushBack(pcon, info);}printf("历史数据已导入通讯录\n");
}void ContactSave(contact* con)
{FILE* pf = fopen("Contact_Info.txt", "wb");if (pf == NULL){perror("fopen error\n");return;}contact* cur = con;while (cur){fwrite(&(cur->data), sizeof(cur->data), 1, pf);cur = cur->next;}printf("成功保存通讯录数据\n");
}void ContactDestory(contact** pcon)
{ContactSave(*pcon);SLDestory(pcon);
}void ContactAdd(contact** pcon)
{ConInfo 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);SLPushBack(pcon, info);printf("已添加联系人数据\n");
}//我们这里通过姓名删除联系人
contact* FindByName(contact* con, char name[])
{contact* cur = con;while (cur){if (strcmp(cur->data.name,name) == 0){return cur;}cur = cur->next;}return NULL;
}void ContactDel(contact** pcon)
{char name[NAME_MAX];printf("请输入你要删除的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(*pcon, name);if (pos == NULL){printf("该联系人不存在\n");return;}SLErase(pcon, pos);printf("已删除该联系人\n");
}void ContactModify(contact* con)
{char name[NAME_MAX];printf("请输入你要修改的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("该联系人不存在\n");return 1;}printf("该联系人姓名修改为:\n");scanf("%s", pos->data.name);	printf("该联系人性别修改为:\n");scanf("%s", pos->data.sex);	printf("该联系人年龄修改为:\n");scanf("%d", &pos->data.age);	printf("该联系人电话修改为:\n");scanf("%s", pos->data.tel);printf("该联系人地址修改为:\n");scanf("%s", pos->data.addr);printf("修改成功\n");
}void ContactFind(contact* con)
{char name[NAME_MAX];printf("请输入你要查找的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("该联系人不存在\n");return;}printf("找到了\n");printf("%s %s %d %s %s\n",pos->data.name,pos->data.sex,pos->data.age,pos->data.tel,pos->data.addr);
}void ContactShow(contact* con)
{printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");contact* cur = con;while (cur){printf("%s %s %d %s %s\n", cur->data.name, cur->data.sex, cur->data.age, cur->data.tel, cur->data.addr);cur = cur->next;}
}

2.5 test.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SList_copy.h"void test1()
{contact *pcontact=NULL;ContactInit(&pcontact);
}void test2()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactAdd(&pcontact);ContactDel(&pcontact);ContactShow(pcontact);}void test3()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactShow(pcontact);ContactAdd(&pcontact);ContactShow(pcontact);ContactDel(&pcontact);ContactShow(pcontact);
}
void test4()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactAdd(&pcontact);ContactAdd(&pcontact);ContactShow(pcontact);ContactFind(pcontact);ContactShow(pcontact);}void test5()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactAdd(&pcontact);ContactShow(pcontact);ContactModify(pcontact);ContactShow(pcontact);ContactDestory(&pcontact);
}void menu()
{printf("\n");printf("****************************\n");printf("****************************\n");printf("************通讯录***********\n");printf("*********1.添加联系人********\n");printf("*********2.删除联系人********\n");printf("*********3.修改联系人********\n");printf("*********4.查找联系人********\n");printf("*********5.查看通讯录********\n");printf("*********0.退  出************\n");printf("****************************\n");printf("****************************\n");
}int main()
{//test1();//test2();//test3();//test4();//test5();int op = 0;contact* con=NULL;ContactInit(&con);do {menu();printf("请选择:\n");scanf("%d", &op);switch (op){case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactModify(con);break;case 4:ContactFind(con);break;case 5:ContactShow(con);break;case 0:printf("退出了哈\n");break;default:printf("输入错误\n");break;}} while (op!=0);ContactDestory(&con);return 0;
}

后言

以上就是小编对单链表应用的一些初步认识。
如果觉得小编讲的还可以,还请一键三连。互三必回!
持续更新中!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/818755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Go】原子并发操作

目录 一、基本概念 支持的数据类型 主要函数 使用场景 二、基础代码实例 开协程给原子变量做加法 统计多个变量 原子标志判断 三、并发日志记录器 四、并发计数器与性能监控 五、优雅的停止并发任务 worker函数 Main函数 应用价值 Go语言中&#xff0c;原子并发操…

【Linux】Linux基础与常用指令大全

文章目录 操作系统是什么&#xff1f;1. Linux家族介绍2. Linux的安装方式3. 常用指令3.1 ls [选项] [目录/文件]&#xff08;显示目录或文件信息&#xff09;3.2 pwd&#xff08;显示当前所在目录&#xff09;3.3 任意指令加上 --help&#xff08;查看指令的用法&#xff09;3…

ThinkPHP V5.1框架源码

源码下载地址&#xff1a;ThinkPHP V5.1.zip www WEB部署目录&#xff08;或者子目录&#xff09; ├─application 应用目录 │ ├─common 公共模块目录&#xff08;可以更改&#xff09; │ ├─module_name 模块目录 │ │ ├─common.php 模块函数文件 │ │ ├─controll…

一文掌握 React 开发中的 JavaScript 基础知识

前端开发中JavaScript是基石。在 React 开发中掌握掌握基础的 JavaScript 方法将有助于编写出更加高效、可维护的 React 应用程序。 在 React 开发中使用 ES6 语法可以带来更简洁、可读性更强、功能更丰富,以及更好性能和社区支持等诸多好处。这有助于提高开发效率,并构建出更…

线性表概念及顺序表的实现

文章目录 前言一、线性表1.定义2.特点3.一般线性表的抽象数据类型定义 二、线性表的顺序存储&#xff08;顺序表&#xff09;1.基本概念2.数组实现顺序表3.顺序表中基本操作的具体实现4.顺序表总结 总结 前言 T_T此专栏用于记录数据结构及算法的&#xff08;痛苦&#xff09;学…

MyBatis 源码分析系列文章导读

1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章。本篇文章从 MyBatis 是什么&#xff08;what&#xff09;&#xff0c;为什么要使用&#xff08;why&#xff09;&#xff0c;以及如何使用&#xff08;how&#xff09;等三个角度进行了说明和演…

记一次对某高校微信小程序的漏洞挖掘

挖掘目标的部署在微信的资产(减少信息的收集&#xff0c;毕竟一般web站点没有账号密码不好进入后台&#xff0c;挖掘功能点少) 寻找目标的微信小程序(非原图) 招生小程序打不开&#xff0c;只能挖掘管理系统 进入后发现存在上报安全隐患功能&#xff0c;可以上传图片 准备上传…

【面经】操作系统/Linux

1、计算机的五大单元 电脑的五大单元包括&#xff1a;输入单元、输出单元、控制单元、算数逻辑单元、存储单元五大部分。其中CPU占有控制、算术逻辑单元&#xff0c;存储单元又包含内存与辅助内存&#xff1b; 2、什么是操作系统 操作系统&#xff1a;负责管理协调我们计算机…

Qt QStyle详解

1.简介 QStyle类是 Qt 框架中用于控制应用程序界面元素外观的一个抽象基类。这个类提供了一种方式来定制窗口部件&#xff08;widgets&#xff09;的绘制和行为&#xff0c;可以通过改变主题或风格来更改应用程序的外观&#xff0c;而无需修改窗口部件本身的代码。 Qt包含一组…

python爬虫------- Selenium下篇(二十三天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

CAN帧中的ACK位

1&#xff1a;先看官方文档对ACK的解释 All nodes that have received the matching CRC sequence (and, in FD Frames the matching stuff count) shall send an ACK within the ACK slot by overwriting the recessive bit of the transmitter by a dominant bit (they send…

求圆、圆球和圆柱的面积和体积(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> //定义π常量的值&#xff1b; # define π 3.141526int main() {//初始化变量值&#xff1b;float r, h, S1, S2, P1, V1, V2;int judge 0;//提示用户&#x…

Python基于flask的豆瓣电影分析可视化系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

mid_360建图和定位

录制数据 roslaunch livox_ros_driver2 msg_MID360.launch使用fast-lio 建图 https://github.com/hku-mars/FAST_LIO.git 建图效果 使用python做显示 https://gitee.com/linjiey11/mid360/blob/master/show_pcd.py 使用 point_lio建图 https://github.com/hku-mars/Point…

【数据结构】【C++】AVL树的模拟实现(插入、判断、旋转)

文章目录 1 概念2 实现2.1 AVL树结点的定义2.2 AVL树的插入2.2.1 AVL树的插入规则2.2.2 旋转2.2.2.1 左单旋2.2.2.2 右单旋2.2.2.3 左右双旋2.2.2.4 右左双旋 2.2.3 总结 3 平衡判断4 删除5 源码 1 概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二…

找不到api-ms-win-crt-runtime-l1-1-0.dll文件5种解决方法

在日常使用计算机的过程中&#xff0c;我们时常会遭遇各类意想不到的问题&#xff0c;其中之一就是“api-ms-win-crt-runtime-l1-1-0.dll丢失”。这个错误通常发生在Windows操作系统中&#xff0c;它表示一个动态链接库文件丢失或损坏。这个问题可能会导致某些应用程序无法正常…

1Panel官方出品丨MaxKB:基于LLM大模型的知识库问答系统

1Panel&#xff08;github.com/1Panel-dev/1Panel&#xff09;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;它致力于通过开源的方式&#xff0c;帮助用户简化建站与运维管理流程。为了方便广大用户快捷安装部署相关软件应用&#xff0c;1Panel特别开通应用商店&am…

TensorFlow 1.x的学习

.为什么还有很多人都选择使用TensorFlow 1.x 兼容性问题: TensorFlow 1.x在一些旧项目中已经得到了广泛应用&#xff0c;这些项目可能依赖于1.x版本的特定API或行为。升级到2.x可能需要大量的代码修改和测试工作&#xff0c;对于一些已经稳定运行的项目&#xff0c;维护者可能…

实现iOS App代码混淆

简介 在开发iOS应用程序时&#xff0c;保护代码安全是至关重要的。代码混淆是一种常用的技术&#xff0c;可以增加逆向工程的难度&#xff0c;防止他人对代码的篡改和盗用。本文将介绍如何实现iOS App代码混淆的步骤和操作方法。 整体流程 下面是实现iOS App代码混淆的整体流…

创维:在博鳌论坛 叩响世界之门

出走半生&#xff0c;归来仍是少年。 2024年4月8日&#xff0c;一个离开海南近半个世纪的“少年”回到琼海博鳌&#xff0c;“下一站&#xff0c;1000亿&#xff01;”&#xff0c;他的承诺掷地有声。“1000亿”&#xff0c;意指创维集团在2025年前冲击千亿营收&#xff0c;这…