C语言进阶(八)—— 链表
1. 链表基本概念
1.1 什么是链表

链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性(非顺序存储)。
数据域用来存储数据,指针域用于建立与下一个结点的联系。
建立链表时无需预先知道数据总量的,可以随机的分配空间,可以高效的在链表中的任意位置实时插入或删除数据。
链表的开销,主要是访问顺序性和组织链的空间损失。
数组和链表的区别:
数组:一次性分配一块连续的存储区域。
优点:随机访问元素效率高
缺点:1) 需要分配一块连续的存储区域(很大区域,有可能分配失败)
2) 删除和插入某个元素效率低
链表:无需一次性分配一块连续的存储区域,只需分配n块节点存储区域,通过指针建立关系。
优点:1) 不需要一块连续的存储区域
2) 删除和插入某个元素效率高
缺点:随机访问元素效率低
1.2 有关结构体的自身引用
问题1:请问结构体可以嵌套本类型的结构体变量吗?
问题2:请问结构体可以嵌套本类型的结构体指针变量吗?
typedef struct _STUDENT{char name[64];int age;
}Student;typedef struct _TEACHER{char name[64];Student stu; //结构体可以嵌套其他类型的结构体//Teacher stu;//struct _TEACHER teacher; //此时Teacher类型的成员还没有确定,编译器无法分配内存struct _TEACHER* teacher; //不论什么类型的指针,都只占4个字节,编译器可确定内存分配
}Teacher;结构体可以嵌套另外一个结构体的任何类型变量;
结构体嵌套本结构体普通变量(不可以)。本结构体的类型大小无法确定,类型本质:固定大小内存块别名;
结构体嵌套本结构体指针变量(可以), 指针变量的空间能确定,32位, 4字节、 64位, 8字节;
1.3 链表节点
大家思考一下,我们说链表是由一系列的节点组成,那么如何表示一个包含了数据域和指针域的节点呢?
链表的节点类型实际上是结构体变量,此结构体包含数据域和指针域:
数据域用来存储数据;
指针域用于建立与下一个结点的联系,当此节点为尾节点时,指针域的值为NULL;
typedef struct Node
{//数据域int id;char name[50];//指针域struct Node *next;
}Node;
1.4 链表的分类
链表分为:静态链表和动态链表
静态链表和动态链表是线性表链式存储结构的两种不同的表示方式:
所有结点都是在程序中定义的,不是临时开辟的,也不能用完后释放,这种链表称为“静态链表”。
所谓动态链表,是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。
1.4.1 静态链表
typedef struct Stu
{int id; //数据域char name[100];struct Stu *next; //指针域
}Stu;void test()
{//初始化三个结构体变量Stu s1 = { 1, "yuri", NULL };Stu s2 = { 2, "lily", NULL };Stu s3 = { 3, "lilei", NULL };s1.next = &s2; //s1的next指针指向s2s2.next = &s3;s3.next = NULL; //尾结点Stu *p = &s1;while (p != NULL){printf("id = %d, name = %s\n", p->id, p->name);//结点往后移动一位p = p->next; }
}1.4.2 动态链表
typedef struct Stu{int id; //数据域char name[100];struct Stu *next; //指针域
}Stu;void test(){//动态分配3个节点Stu *s1 = (Stu *)malloc(sizeof(Stu));s1->id = 1;strcpy(s1->name, "yuri");Stu *s2 = (Stu *)malloc(sizeof(Stu));s2->id = 2;strcpy(s2->name, "lily");Stu *s3 = (Stu *)malloc(sizeof(Stu));s3->id = 3;strcpy(s3->name, "lilei");//建立节点的关系s1->next = s2; //s1的next指针指向s2s2->next = s3;s3->next = NULL; //尾结点//遍历节点Stu *p = s1;while (p != NULL){printf("id = %d, name = %s\n", p->id, p->name);//结点往后移动一位p = p->next; }//释放节点空间p = s1;Stu *tmp = NULL;while (p != NULL){tmp = p;p = p->next;free(tmp);tmp = NULL;}
}1.4.3 带头和不带头链表
带头链表:固定一个节点作为头结点(数据域不保存有效数据),起一个标志位的作用,以后不管链表节点如果改变,此头结点固定不变

不带头链表:头结点不固定,根据实际需要变换头结点(如在原来头结点前插入新节点,然后,新节点重新作为链表的头结点)。

1.4.4 单向链表、双向链表、循环链表
单向链表:

双向链表:

循环链表:

2. 链表基本操作
2.1 创建链表
使用结构体定义节点类型:
typedef struct _LINKNODE
{int id; //数据域struct _LINKNODE* next; //指针域
}link_node;编写函数:link_node* init_linklist()
建立带有头结点的单向链表,循环创建结点,结点数据域中的数值从键盘输入,以 -1 作为输入结束标志,链表的头结点地址由函数值返回。
typedef struct _LINKNODE{int data;struct _LINKNODE* next;
}link_node;link_node* init_linklist(){//创建头结点指针link_node* head = NULL;//给头结点分配内存head = (link_node*)malloc(sizeof(link_node));if (head == NULL){return NULL;}head->data = -1;head->next = NULL;//保存当前节点link_node* p_current = head;int data = -1;//循环向链表中插入节点while (1){printf("please input data:\n");scanf("%d",&data);//如果输入-1,则退出循环if (data == -1){break;}//给新节点分配内存link_node* newnode = (link_node*)malloc(sizeof(link_node));if (newnode == NULL){break;}//给节点赋值newnode->data = data;newnode->next = NULL;//新节点入链表,也就是将节点插入到最后一个节点的下一个位置p_current->next = newnode;//更新辅助指针p_currentp_current = newnode;}return head;
}2.2 遍历链表
编写函数:void foreach_linklist(link_node* head)
顺序输出单向链表各项结点数据域中的内容:
//遍历链表
void foreach_linklist(link_node* head){if (head == NULL){return;}//赋值指针变量link_node* p_current = head->next;while (p_current != NULL){printf("%d ",p_current->data);p_current = p_current->next;}printf("\n");
}2.3 插入节点
编写函数: void insert_linklist(link_node* head,int val,int data)
在指定值后面插入数据data,如果值val不存在,则在尾部插入:li
//在值val前插入节点
void insert_linklist(link_node* head, int val, int data){if (head == NULL){return;}//两个辅助指针link_node* p_prev = head;link_node* p_current = p_prev->next;while (p_current != NULL){if (p_current->data == val){break;}//两个辅助指针向后p_prev = p_current;p_current = p_prev->next;}//如果p_current为NULL,说明不存在值为val的节点//if (p_current == NULL){// printf("不存在值为%d的节点!\n",val);// return;//}//创建新的节点link_node* newnode = (link_node*)malloc(sizeof(link_node));newnode->data = data;newnode->next = NULL;//新节点入链表newnode->next = p_current;p_prev->next = newnode;
}2.4 删除节点
编写函数: void remove_linklist(link_node* head,int val)
删除第一个值为val的结点:
//删除值为val的节点
void remove_linklist(link_node* head,int val){if (head == NULL){return;}//辅助指针link_node* p_prev = head;link_node* p_current = p_prev->next;//查找值为val的节点while (p_current != NULL){if (p_current->data == val){break;}p_prev = p_current;p_current = p_prev->next;}//如果p_current为NULL,表示没有找到if (p_current == NULL){return;}//删除当前节点: 重新建立待删除节点(p_current)的前驱后继节点关系p_prev->next = p_current->next;//释放待删除节点的内存free(p_current);
}2.5 销毁链表
编写函数: void destroy_linklist(link_node* head)
销毁链表,释放所有节点的空间:
//销毁链表
void destroy_linklist(link_node* head){if (head == NULL){return;}//赋值指针link_node* p_current = head;while (p_current != NULL){//缓存当前节点下一个节点link_node* p_next = p_current->next;free(p_current);p_current = p_next;}
}2.6 反转链表
编写函数: void reverse_linklist(link_node* head)
反转链表通过3个辅助指针变量实现链表的翻转:
void reverse_linklist(link_node* head){if (head == NULL){return;}//辅助指针link_node* p_prev = NULL;link_node* p_current = head->next;link_node* p_next = NULL;while (p_current != NULL){p_next = p_current->next;//更改指针指向p_current->next = p_prev;//移动辅助指针p_prev = p_current;p_current = p_next;}//更新头结点head->next = p_prev;
}2.7 统计链表长度
编写函数: int size_linklist(link_node* head)
int size_linklist(link_node* head){if (head == NULL){return -1;}//临时指针变量执行第一个真实数据的结点link_node* p_current = head->next;//记录结点个数int num = 0;while (p_current != null) {num++;p_current = p_current->next;}return num;
}
相关文章:
C语言进阶(八)—— 链表
1. 链表基本概念1.1 什么是链表链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性(非顺序存储)。数据域用来存储数据,指针域用于建立与下一个结点的…...
手工测试用例就是自动化测试脚本——使用ruby 1.9新特性进行自动化脚本的编写
昨天因为要装watir-webdriver的原因将用了快一年的ruby1.8.6升级到了1.9。由于1.9是原生支持unicode编码,所以我们可以使用中文进行自动化脚本的编写工作。 做了简单的封装后,我们可以实现如下的自动化测试代码。请注意,这些代码是可以正确运…...
RockerMQ简介和单节点部署
目录一、RockerMQ简介二、Linux中单节点部署1、准备工作2、下载和解压3、修改初始内存4、启动5、查看进程6、发送接收消息测试7、关闭三、控制台的安装与启动(可视化页面)1、修改配置(1)修改端口号(2)指定RocketMQ的name server地…...
SFP光纤笼子 别称 作用 性能要点 工程要素
Hqst盈盛电子导读:2023年,Hqst盈盛电子于下属五金部开发生产SFP光纤连接器笼子等系列产品,所有产品生产及性标准都将参照连接器产品常用测试标准EIA-364-C等标准,以下为我司常规SFP光纤连接器基本性能要求SFP光纤笼子别称…...
[HarekazeCTF2019]Easy Notes
知识点:session 反序列化,代码审计代码分析 flag.php 中有个 is_admin 函数的判断。 在 lib.php 中有 is_admin 函数,需要 session[admin] 为 true,或者通过文件读取的方式。 在 index.php 中的 include 并不能使用伪协议读取 …...
Java学习-IO流-字符流-FileReader
Java学习-IO流-字符流-FileReader 字符流 字节流 字符集 输入流:默认一次读一个字节,遇到中文时一次读多个字节 输出流:底层把数据按照指定编码方式编码,变成字节写入文件 使用场景:纯文本文件读写 // …...
python攻陷米哈游《元神》数据?详情请看文章。。
前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 《原神》是由米哈游自研的一款全新开放世界冒险RPG。 里面拥有许多丰富得角色,让玩家为之着迷~ 今天,我们就来用python探索一下原神游戏角色信息! 标题大家看看就好了哈~(…...
【unity细节】基于unity子对象(如相机)为什么无法进行z轴的拖拽移动和z轴自动归位的问题
👨💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 收录于专栏:unity细节和bug ⭐基于unity子对象为什么无法进行z轴的拖拽移动和z轴自动归位⭐ 文章目录⭐基于u…...
如何维护固态继电器?
固态继电器是SSR的简称,是由微电子电路、分立电子器件和电力电子功率器件组成的非接触式开关。隔离装置用于实现控制端子与负载终端之间的隔离。固态继电器的输入端使用微小的控制信号直接驱动大电流负载。那么,如何保养固态继电器呢? 在为小…...
Sprng依赖注入(三):构造方法注入是如何工作的?
前言这是Spring依赖注入系列的第三篇,前两篇主要分析了Spring bean依赖属性注入的两种方式,是字段注入和setter方法注入,单独比较这两种方式,会发现其过程和工作原理非常类似,那么构造方法注入会不会也和前两种比较类似…...
「1」指针进阶——详解
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀 目录 🐰指针的回顾 🐰字符指针 🐰指针数组 🌸模…...
JS语法让人困惑的点 “==与===”
在JS中有很多神奇的语法,非常让人困惑,我们就先一一道来,相信你在开发中或多或少都踩过这些坑,或者让人无法理解。 今天我们就来说下【】和【】 这题对于很多没有系统学过前端开发的技术人员来说,算个重点,…...
《狂飙》壁纸大嫂如此惊艳,做成日历壁纸天天看
兄弟们,今年的反腐大剧狂飙都有看吗 ? 话说,名字虽然叫狂飙,但是全剧只有有田一个人在狂飙! 当然,有田虽然亮眼,但是毕竟是个糟老头子,正经人谁看有田啊,当然是看大嫂了…...
手机照片删除了怎么恢复
手机照片删除了怎么恢复?喜欢拍照的小伙伴,都会不定期删除手机上的照片,因为这些爱拍照的人,手机中会存储着很多照片,删除照片是必然的,但在手机删除照片时,如果是一张一张删除太麻烦了,就直接…...
maven pom.xml 依赖的scope属性
maven pom.xml 依赖的scope属性 compile 适用范围 编译期、测试期、运行期 作用 从中央仓库拉取依赖到本地,并编译 打包到结果包中 runtime 适用范围 测试期、运行期 作用 runtime 用在 Class.forName(“com.mysql.jdbc.Driver”) 时,compile 编…...
git 的使用方法 (下 - 远程仓库和图形化)
目录前言:一、什么是协同开发二、Gitee 使用协同开发1. 首先注册一个码云账号2. 新建一个仓库3. 根据下图把新建仓库设置为开源4. 在远端合并分支的方法5. 链接 git 远程6. 提交(同步)远程7. 远程拉取至本地8. 远程分支三、git 图形化的使用1…...
Java基础:拼图小游戏
涉及到的知识: 1.图形用户接口GUI(Graphical User Interface)用图形化的方式显示操作界面 两个体系: AWT包和Swing包 2.界面会用到JFrame类 3.界面中的菜单会用到JMenuBar, JMenu, JMenuItem 4.添加图片 在设置完JLabel的location之后还需要获得展示内容的窗体, 通过setLay…...
一个跟蘑菇结缘的企业老板
记得那是一个很久以前的一家公司了董事长办公室里中的大型盆栽里面长了一个蘑菇董事长认为是祥瑞每天都会浇水后来一个新来的保洁阿姨以为杂草啥的给他掰掉扔垃圾桶了董事长第二天来浇水的时候发现没了就问谁动了他的蘑菇问道之后就跑到楼道大垃圾桶那里把蘑菇找回来种在花盆里…...
【Leetcode 剑指Offer】第 4 天 查找算法(简单)
查找剑指 Offer 03. 数组中重复的数字剑指 Offer 53 - I. 在排序数组中查找数字 I二分法题目链接剑指 Offer 03. 数组中重复的数字 题:在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数…...
Jenkins利用docker部署vue项目
Jenkins利用docker部署vue项目一、环境准备1、安装docker2、安装nodejs3、安装cnpm与配置淘宝镜像4、jenkins安装nodejs插件二、jenkins以vue项目1、全局参数配置2、源码配置3、构建环境4、构建三、构建项目四、访问一、环境准备 本次jenkins与部署vue项目在同一台机器&#x…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
