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

C语言菜鸟入门·数据结构·链表超详细解析

 

目录

1.  单链表

1.1  什么是单链表

1.1.1  不带头节点的单链表

1.1.2  带头结点的单链表

1.2  单链表的插入

1.2.1  按位序插入

(1)带头结点

(2)不带头结点

1.2.2  指定结点的后插操作

1.2.3  指定结点的前插操作

1.3  单链表的删除

1.3.1  按位序删除

1.3.2  指定结点的删除


1.  单链表

1.1  什么是单链表

        对比于顺序表的每个节点只存放数据元素,单链表的每个节点除了存放数据元素外,还要存储指向下一个节点的指针。

顺序表:

优点:可随机存储,存储密度较高;

缺点:要求大片连续空间,改变容量不方便。

单链表:

优点:不要求大片连续空间,改变容量方便;

缺点:不可随机存取,要耗费一定空间存放指针。

        对于单链表的每一个结点,都需要有一个数据域用于存放节点的数据元素,需要一个指针域用于指向下一个结点。

struct LNode{ElemType data;struct LNode *next;
};

对于struct关键字的用法可参考:C语言菜鸟入门·结构体·struct用法超详细解析_c语言数据结构菜鸟-CSDN博客

        而若是我们想要增加一个新的结点,我们可以使用malloc关键字,例如:

        首先,我们先声明一个指向struct LNode类型的对象p,通过malloc函数动态分配内存大小为struct LNode类型大小的内存。

struct LNode* p=(struct LNode*)malloc(sizeof(struct LNode));

        对于每次增加一个新的结点,我们每次都需要加上struct LNode这样声明起来有些太麻烦了。那么要怎么简单点呢?我们可以使用typedef进行重命名操作,那么就可以写为:

struct LNode{ElemType data;struct LNode *next;
}LNode,*LinkList;

其中对于typedef的操作可以参考:C语言菜鸟入门·各种typedef用法超详细解析-CSDN博客中的结构体介绍。

1.1.1  不带头节点的单链表

        我们使用typedef后,可以开始创建一个不带头节点的单链表:

struct LNode{ElemType data;struct LNode *next;
}LNode,*LinkList;//初始化一个空链表
bool InitList(LinkList &L)
{L = NULL;  //空表,按时还没任何结点,防止脏数据return trun;
}void test()
{Linklist L;//声明一个指向单链表的指针,注意此处没有创建一个结点//初始化一个空表InitList(L);//····后续代码····
}

        其作用是判断单链表是否为空,通过头指针L,初始化一个空表,防止脏数据:

        其中初始化一个空链表的代码也可以写为:

bool Empty(LinkList L)
{if(L==NULL)return true;elsereturn true;        
}

        或者:

bool Empty(LinkList L)
{return (L==NULL);      
}

1.1.2  带头结点的单链表

struct LNode{ElemType data;struct LNode *next;
}LNode,*LinkList;//初始化一个空链表
bool InitList(LinkList &L)
{L = (LNode*)malloc(sizeof(LNode));//分配一个头节点if(L == NULL)//内存不足,分配失败return false;L->next = NULL;//头结点之后暂时还没有结点return true;}void test()
{Linklist L;//声明一个指向单链表的指针//初始化一个空表InitList(L);//····后续代码····
}

        不带头结点的头指针指向的下一个结点,这个结点就是实际用于存放数据的结点,

        带头节点的头指针指向的下一个结点,这个结点不用来存放实际的数据元素的,只有这个结点的下一个结点才会用来存放数据。

1.2  单链表的插入

1.2.1  按位序插入

(1)带头结点

        插入操作,例如在表L中的第i个位置上插入指定元素e:

Listlnsrrt(&L,i,e);

        我们要如何来实现插入操作呢?我们要想在i个位置上插入,那么我们就需要找到第i-1个结点,将新的节点插入其后,假设我们的i=2的话(a2),那么我们就需要找到其前一个结点(a1)的结点,然后我们使用malloc函数,申请一个新的结点,往这个结点存入指针e,然后修改指针,就可以得到:

struct LNode {ElemType data;struct LNode* next;
}LNode, * LinkList;//在第i个位置上插入元素e(带头结点)
bool ListInsert(LinkList& L, int i, ElemType e)
{if (i<1)return false;LNode* p;//指针p指向当前扫描到的结点int j = 0;//指针p指向第几个结点p = L;//L指向头结点,头结点是第0个结点(不存数据)while (p != NULL && j < i - 1)//循环找到第i-1个结点{p = p->next;j++;}if(p==NULL)//i值不合法return false;LNode* s = (LNode*)malloc(sizeof(LNode));s->date = e;s -> next = p->next;//将结点s连接到p之后p -> next = s;//插入成功return true;}

    s->date = e;s -> next = p->next;//将结点s连接到p之后p -> next = s;//插入成功

(2)不带头结点

        由于不带头结点,所以不存在头结点是0的情况,那么数据处理为:

struct LNode {ElemType data;struct LNode* next;
}LNode, * LinkList;//在第i个位置上插入元素e(带头结点)
bool ListInsert(LinkList& L, int i, ElemType e)
{if (i<1)return false;if (i == 1)//插入第1个节点的操作与其他结点操作不同{LNode* s = (LNode*)malloc(sizeof(LNode));s->date = e;s - next = L;L = s;return true;}LNode* p;//指针p指向当前扫描到的结点int j = 1;//指针p指向第几个结点p = L;//L指向头结点,头结点是第0个结点(不存数据)while (p != NULL && j < i - 1)//循环找到第i-1个结点{p = p->next;j++;}if(p==NULL)//i值不合法return false;LNode* s = (LNode*)malloc(sizeof(LNode));s->date = e;s -> next = p->next;//将结点s连接到p之后p -> next = s;//插入成功return true;}

1.2.2  指定结点的后插操作

        后插操作比较简单,对比按位序插入,仅仅将其改为指定插入,就明确告诉你我要插哪里:

struct LNode {ElemType data;struct LNode* next;
}LNode, * LinkList;bool InsertNextNode(LinkList* p, ElemType e)
{if(p==NULL)return false;LNode* s = (LNode*)malloc(sizeof(LNode));if(s==NULL)return false;s->date = e;s -> next = p->next;p -> next = s;return true;
}

1.2.3  指定结点的前插操作

        在链表中,我们并不能通过后一节点的数据data找到,前一个结点的指针域next,那我们要如何实现前插操作呢?

例如:我们想在结点1之前插入一个结点:

        首先,我们先创建一个结点:

         然后,我们既然找不到前驱结点,干脆不找了,直接将结点1的数据data1以及指针域next1复制到新建的结点,这样复制的结点数据就和结点1的数据相同:

        然后我们在将想要插入的结点赋值给结点1:

        然后将插入结点的next指向复制的结点1的data,让复制的结点1的next指向结点2的data,此时的复制结点1和结点1是相同的,结点插在复制的结点1之前,等价于结点插,插入到结点1之前:

struct LNode {ElemType data;struct LNode* next;
}LNode, * LinkList;bool InsertNextNode(LinkList* p, ElemType e)
{if(p==NULL)return false;LNode* s = (LNode*)malloc(sizeof(LNode));if(s==NULL)return false;s -> next = p->next;p -> next = s;s->date = p->data;p->data = e;return true;
}

1.3  单链表的删除

1.3.1  按位序删除

        删除操作,删除表L中的第i个位置的元素,并用e返回删除元素的值:

ListDelete(&L,i,&e);

        简单来说就是找到第i-1个结点,将其指针指向第i+1个结点,并释放第i个结点。

struct LNode {ElemType data;struct LNode* next;
}LNode, * LinkList;bool ListDelete(LinkList& L, int i, ElemType &e)
{if (i<1)return false;LNode* p;//指针p指向当前扫描到的结点int j = 0;//指针p指向第几个结点p = L;//L指向头结点,头结点是第0个结点(不存数据)while (p != NULL && j < i - 1)//循环找到第i-1个结点{p = p->next;j++;}if(p==NULL)//i值不合法return false;if (p->next == NULL)//第i-1个结点之后已无其他结点return false;LNode* q = p->next;//令q指向被删除的结点e = q->date;//用e返回元素的值p - next = q->next;//将*q结点从链中“断开”free(q);//释放结点的存储空间return true;}

1.3.2  指定结点的删除

        指定结点的删除,删除结点p,需要修改其前驱节点的next指针。有两种方法:

方法1:传入头指针,循环寻找p的前驱结点;

方法2:类似于结点前插的实现方式。

bool DeleteNode(LNode *p)
{if(p==NULL)//i值不合法return false;LNode* q = p->next;//令q指向*p的后续结点p->date = p -> next->date;//和后续结点交换数据域p -> next = q->next;//将*q结点从链中“断开”free(q);//释放结点的存储空间return true;
}

        但是以上代码,若是p是最后一个节点,那么代码:

    p->date = p -> next->date;//和后续结点交换数据域

        就会发生错误,解决方法:我们就只能从表头开始一次寻找p的前驱。

C语言_时光の尘的博客-CSDN博客

相关文章:

C语言菜鸟入门·数据结构·链表超详细解析

目录 1. 单链表 1.1 什么是单链表 1.1.1 不带头节点的单链表 1.1.2 带头结点的单链表 1.2 单链表的插入 1.2.1 按位序插入 &#xff08;1&#xff09;带头结点 &#xff08;2&#xff09;不带头结点 1.2.2 指定结点的后插操作 1.2.3 指定结点的前插操作 1.3 …...

C# Unity 面向对象补全计划 七大原则 之 依赖倒置原则 (DIP)难度:☆☆ 总结:多抽象,多接口,少耦合

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识&#xff0c;看不懂没关系 请看专栏&#xff1a;http://t.csdnimg.cn/mIitr&#xff0c;查漏补缺 1.依赖倒置原则 (DIP) 这…...

大模型面试问题

综合基础 1、讲讲制作一个LLM的流程以及各阶段的作用 2、发现模型性能不好&#xff0c;如何从各个阶段去排查问题 查看各阶段中是否有对应训练数据&#xff0c;然后再向下排查。预训练 1、Transfomer模型介绍一下 2、讲讲 Q、K、V 3、Transfomer模型中Encoder输出给Decoder的…...

keeplive配置详解与haproxy配置详解

一、keepalive相关知识 1.1 keepalive介绍 keepalive即LVS集群当中的高可用架构&#xff0c;只是针对调度器的高可用。是高可用的HA架构。 keepalive就是基于VRRP协议来实现LVS高可用的方案。 1、组播地址 224.0.0.18&#xff0c;根据组播地址进行通信&#xff0c;主备之间发…...

vivado里的LUT、LUTRAM、FF、BRAM、DSP、IO、BUFG、MMCM资源介绍

vivado里的LUT、LUTRAM、FF、BRAM、DSP、IO、BUFG、MMCM资源介绍 提示&#xff1a;以下是本篇文章正文内容&#xff0c;写文章实属不易&#xff0c;希望能帮助到各位&#xff0c;转载请附上链接。 vivado实现电路用到的资源类型 LUT&#xff08;Look-Up Table&#xff09;&am…...

window关闭端口占用

文章目录 一、打开命令行&#xff0c;输入命令&#xff0c;得到进程号二、找到其端口并杀死该端口总结 一、打开命令行&#xff0c;输入命令&#xff0c;得到进程号 winr打开命令行&#xff0c;输入命令 netstat -ano | findstr 端口号得到端口号 二、找到其端口并杀死该端…...

Java:类和对象

类和对象 类&#xff08;Class&#xff09;类的定义 对象&#xff08;Object&#xff09;对象的创建 构造方法&#xff08;Constructor&#xff09;构造方法的定义 继承&#xff08;Inheritance&#xff09;继承的示例 总结示例一设想一个场景&#xff1a;创建一个虚拟动物园一…...

Pandas数据分析案例之用户购买记录分析

文章目录 数据分析之用户购买记录分析第一部分&#xff1a;数据类型处理数据加载观察数据查看数据的数据类型数据中是否存储在缺失值将order_dt转换成时间类型查看数据的统计描述计算所有用户购买商品的平均数量计算所有用户购买商品的平均花费 在源数据中添加一列表示月份:ast…...

串口调试可能遇见的常见问题和排查方法

串口UART作为嵌入式应用和通讯领域中最常用的接口之一&#xff0c;接口协议虽然简单&#xff0c;但在实际应 用中不同设备之间的通讯也会存在各种小问题&#xff0c;下面对使用中各种常见的问题做下总结和梳 理&#xff0c;可作为调试参考。 01串口通信常见问题 串口通信乱码…...

运放学习提纲

目的&#xff1a;给初入硬件的朋友一个系统性学习运放的参考方向&#xff0c;避免像无头苍蝇那般 一&#xff1a;偏置电流 1.1. 为什么是输入偏置电流&#xff1f; 1.2. 什么是输入偏置电流&#xff1f; 1.3. 怎么搜索资料&#xff1f;怎么把 ADI 模型导 入Multisim &#…...

nvidia系列教程-AGX-Orin系统刷机及备份

目录 前言 一、准备工作 二、AGX Orin 系统刷机步骤 三、AGX Orin 系统备份 总结 前言 NVIDIA AGX Orin 是一款高性能的嵌入式计算平台&#xff0c;专为边缘计算和 AI 应用而设计。为了确保系统的稳定性和适应不同的应用场景&#xff0c;用户可能需要对 AGX Orin 进行系统刷…...

将 Mojo 与 Python 结合使用

Mojo 允许您访问整个 Python 生态系统,但环境可能会因 Python 的安装方式而异。花些时间准确了解 Python 中的模块和包的工作原理是值得的,因为有一些复杂情况需要注意。如果您以前在调用 Python 代码时遇到困难,这将帮助您入门。 Python 中的模块和包 让我们从 Python 开始…...

Unrecognized option: --add-opens=java.base/java.lang=ALL-UNNAMED

Unrecognized option: --add-opensjava.base/java.langALL-UNNAMED Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. Disconnected from server 报错原因&#xff1a;这里我是启动一个SpringBoot项目的时候报这…...

js与ios、安卓原生方法互调。

注意方法名与参数需要与对方约束 1.js调用安卓原生方法 window.android.方法名&#xff08;要传递的参数&#xff09; 调用安卓方法并且传递参数过去&#xff1a;window.WebAppInterface.安卓方法("参数") window.安卓暴露的方法function(安卓传递过来的参数){} …...

C++——多态经典案例(二)制作饮品

案例&#xff1a;制作饮品的步骤是差不多一样的&#xff0c;假设都有四步&#xff0c;打开包装Open、煮水Boil、放杯子里面PutInCup、放佐料PutSomething、喝Drink 利用多态&#xff0c;制作茶和咖啡等饮品 分析&#xff1a;定义一个抽象类&#xff0c;纯虚函数包括Open、Boil…...

内网域森林之ProxyNotShell漏洞利用

点击星标&#xff0c;即时接收最新推文 本文选自《内网安全攻防&#xff1a;红队之路》 在渗透测试过程&#xff0c;如果目标环境存在Exchange服务器&#xff0c;我们也需要测试是否存在已知的远程命令执行漏洞&#xff0c;这里首先介绍ProxyNotShell。 ProxyNotShell和之前…...

SpringBoot基础 第一天

SpringBoot配置的文件名是固定的&#xff1a;application.yml application.properties YAML:以数据为中心 比Json xml更适合做配置文件 YAML语法: 1 字面量:普通值(字符串 布尔值 数字) (1) k: v (2) " "不会转义 会转义 2 对象&#xff0c;map(属性和值) (1)…...

【C/C++】C语言和C++实现Stack(栈)对比

我们初步了解了C&#xff0c;也用C语言实现过栈&#xff0c;就我们当前所更新过的有关C学习内容以栈为例子&#xff0c;来简单对比一下C语言和C。 1.C中栈的实现 栈的C语言实现在【数据结构】栈的概念、结构和实现详解-CSDN博客 &#xff0c;下面是C实现的栈&#xff0c; 在St…...

mysql定时备份脚本

概述 整理Mysql数据库备份脚本&#xff0c;用在生产环境数据库定时备份。 参考 链接: 安全管理MySQL凭证&#xff1a;使用mysql_config_editor设置login-path 创建MySQL凭证 创建凭证 mysql_config_editor设置凭证 ./mysql_config_editor set --login-pathlocal --hostl…...

云原生 (1)

一、实验准备 1&#xff0c;准备一台rhel7的主机,并开启主机的图形。 2&#xff0c;关闭vmware DHCP功能。 3&#xff0c;配置好可用IP。 4&#xff0c;关闭火墙。 二、安装图形化kickstart自动安装脚本的工具 1. 基础配置 yum install system-config-kickstart ——安…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...