【数据结构篇】~单链表(附源码)
【数据结构篇】~链表
- 链表前言
- 链表的实现
- 1.头文件
- 2.源文件
链表前言
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
1、链式机构在逻辑上是连续的,在物理结构上不一定连续
2、结点一般是从堆上申请的
3、从堆上申请来的空间,是按照一定策略分配出来的,每次申请的空间可能连续,可能不连续当我们想要保存一个整型数据时,实际是向操作系统申请了一块内存,这个内存不仅要保存整型数据,也需要保存下一个结点的地址(当下一个结点为空时保存的地址为空)。
当我们想要从第一个结点走到最后一个结点时,只需要在当前结点拿上下一个结点的地址就可以了。
如图:
既然链表是有一个个节点组成的那我们就可以把它看成一个小火车!
链表的实现
1.头文件
#pragma once
#include <stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int sldatatype;//因为不知道要保存什么类型的数据
//定义节点的结构体
typedef struct slistnode {sldatatype data;//保存的数据struct slistnode* next;//指向下一个结构体的指针
}slnode;
void slprint(slnode* phead);
//打印链表(这里要传链表头的地址,以确保能找到链表)
//phead的作用就和火车头差不多
slnode* slbuynode(sldatatype);//申请新节点
void slpushback(slnode** pphead, sldatatype x);
//尾插(因为要通过函数改变数据所以就要传‘址’调用,不能‘传值’)
//所以这里是‘二级’指针!
void slpushfornt(slnode** pphead, sldatatype x);//头插
void slpopback(slnode** pphead);//尾删
void slpopfornt(slnode** pphead);//头删
//查找
slnode* slfind(slnode* phead, sldatatype x);
//在指定位置之前插入数据
void slinsert(slnode** pphead, slnode* pos, sldatatype x);
//删除pos结点
void slerase(slnode** pphead, slnode* pos);
//在指定位置之后插入数据
void slinsertAfter(slnode* pos, sldatatype x);
//删除pos之后的结点
void sleraseAfter(slnode* pos);
//销毁链表
void sldestroy(slnode** pphead);
2.源文件
#include"slist.h"
//断言pphead的目的是不能对空地址进行解引用!
void slprint(slnode* phead)//打印链表
{slnode* pcur = phead;while(pcur){printf("%d->", pcur->data);//打印数据pcur = pcur->next;//改变purc的指向,让它指向下一个节点}printf("NULL\n");
}
slnode* slbuynode(sldatatype x)//申请新节点
{slnode* newnode = (slnode*)malloc(sizeof(slnode));//一开辟空间就要检查是否开辟成功if (newnode==NULL){perror("malloc fail");}newnode->data = x;newnode->next = NULL;return newnode;
}
void slpushback(slnode** pphead,sldatatype x)//尾插(pphead==&plist)
{ slnode* pcur = *pphead;//既然要插入数据那么就要开辟新空间(新节点)slnode* newnode = slbuynode(x);assert(pphead);if (*pphead==NULL)//如果是空链表(plist==null){*pphead = newnode;newnode->data = x;}else//不是空链表{ while (pcur->next){pcur = pcur->next;}newnode->data = x;pcur->next = newnode; }
}
void slpushfornt(slnode** pphead, sldatatype x)//头插
{//既然要插入数据那么就要开辟新空间(新节点)slnode* newnode = slbuynode(x);assert(pphead);newnode->next = *pphead;//为了把新结点和原来的链表连起来*pphead = newnode;
}
void slpopback(slnode** pphead)//尾删
{//删除时,pphead(不能对null进行解引用)和头节点(不然没意义了)都不能为空assert(pphead&&*pphead);if ((*pphead)->next==NULL)//只有一个节点{free(*pphead);(*pphead)->next = NULL;}else{ slnode* ptail = *pphead;slnode* prev = NULL;while (ptail->next)//跳出循环时ptail就是最后一个节点{ prev = ptail;ptail = ptail->next;}prev->next = NULL;free(ptail);ptail = NULL;}
}
void slpopfornt(slnode**pphead)//头删
{//删除时,pphead(不能对null进行解引用)和头节点(不然没意义了)都不能为空assert(pphead && *pphead);slnode* node = (*pphead)->next;//(->)的优先级大于(*(解引用))所以要用()free(*pphead);*pphead = NULL;*pphead = node;
}
//查找
//因为查找数据不需要改变链表内容所以这里传一级指针
slnode* slfind(slnode* phead, sldatatype x)
{assert(phead);//不能在空链表中查找数据slnode* node = phead;while (node){if (x == node->data){return node;}node = node->next;}return NULL;
}
//在指定位置之前插入数据(要改变的指针有pos的前驱节点和pos)
void slinsert(slnode** pphead, slnode* pos, sldatatype x)
{assert(pphead);assert(pos);slnode* newnode = slbuynode(x);if (pos == *pphead)//pos是头节点就调用’头插‘{slpushfornt(pphead,x);}else//pos不是头节点{ slnode* prev = *pphead;//定义pos的前一个节点以便连接while (prev->next!=pos){prev = prev->next;}//出循环就代表pos的前驱节点已找到!newnode->next = pos;prev->next = newnode;}
}
//在指定位置之后插入数据
//在pos后插入数据要改变的指针有(pos、pos->next)
void slinsertAfter(slnode* pos, sldatatype x)
{assert(pos);slnode* newnode = slbuynode(x);slnode* next = pos->next;newnode->next = pos->next;pos->next = newnode;
}
//删除pos结点
//删除pos后改变的指针有(pos的前驱节点和pos的next指针)
void slerase(slnode** pphead, slnode* pos)
{assert(pphead && pos);//不能删除空节点if (pos == *pphead)//如果pos是头节点就进行头删{ slpopfornt(pphead);}else//不是头节点{slnode* prev = *pphead;slnode* next = pos->next;while(prev->next!=pos){prev = prev->next;}//出循环后找到了pos的前驱节点prev->next = next;free(pos);pos = NULL;}}//删除pos之后的结点
//删除pos之后的结点要改变的指针有(pos和pos->next)
void sleraseAfter(slnode* pos)
{assert(pos);slnode* del = pos->next;pos->next = pos->next->next;free(del);del = NULL;
}
//销毁链表
void sldestroy(slnode** pphead)
{assert(pphead&&*pphead);//不能销毁空链表slnode* purc = *pphead;while (purc){slnode* next =purc->next ;free(purc);purc = next; }//头节点还没销毁*pphead = NULL;
}
详解都在注释中哦!
相关文章:

【数据结构篇】~单链表(附源码)
【数据结构篇】~链表 链表前言链表的实现1.头文件2.源文件 链表前言 链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 1、链式机构在逻辑上是连续的,在物理结构上不一定连续 2、结点一般是从…...
旋转图像(LeetCode)
题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 解题 def rotate(matrix):n len(matrix)# 矩阵转置for i in range(n):for…...
入门 - vue中v-model的实现原理和完整用法详解
v-model介绍 v-model是vue的双向绑定的指令,能将页面上控件输入的值同步更新到相关绑定的data属性,也会在更新data绑定属性时候,更新页面上输入控件的值。在view层,model层相互需要数据交互,即可使用v-model。 双向绑…...

【区块链+金融服务】港融区域股权服务平台 | FISCO BCOS应用案例
中国证监会在 2020 年启动了区块链建设试点工作,提出建设基于区块链的场外市场登记系统和交易报告库,利 用区块链去中心化、不易篡改、安全稳定等技术特点,构建区域性股权市场数字化信任机制,为区域性股权市场 提供基础支撑设施。…...
Nginx反向代理和前后端分离项目打包部署
Nginx反向代理 Nginx的定位:主要用于做反向代理,一般都是用它来做前端页面的服务器,动态资源代理到后端服务器。这样做的好处是可以避免跨域请求带来的不便。 使用Nginx主要是对Nginx中的nginx.conf文件进行配置: 虚拟主机配置…...
Spring 中ApplicationContext
ApplicationContext 是 Spring 框架中最重要的接口之一,用于提供 Spring IoC 容器的功能。它是一个比 BeanFactory 更高级的容器,负责管理 Spring bean 的生命周期,同时提供对各种企业服务的集成,例如事件传播、国际化、弱引用等。…...
python之时间 datetime、date、time、timedelta、dateutil
在 Python 中,处理日期和时间的常用库是 datetime。此外,还有一些第三方库如 pytz 和 dateutil 可以帮助处理时区和日期解析。 1. 使用 datetime 模块 导入模块 from datetime import datetime, date, time, timedelta获取当前日期和时间 now datet…...

【机器学习第11章——特征选择与稀疏学习】
机器学习第11章——特征选择与稀疏学习 11.特征选择与稀疏学习11.1子集搜索与评价子集搜索子集评价 11.2 过滤式选择11.3 包裹式选择11.4 嵌入式选择11.5 稀疏表示与字典学习稀疏表示字典学习 11.6 压缩感知 11.特征选择与稀疏学习 11.1子集搜索与评价 特征:描述物…...
LeetCode-day43-3137. K 周期字符串需要的最少操作次数
LeetCode-day43-3137. K 周期字符串需要的最少操作次数 题目描述示例示例1:示例2: 思路代码 题目描述 给你一个长度为 n 的字符串 word 和一个整数 k ,其中 k 是 n 的因数。 在一次操作中,你可以选择任意两个下标 i 和 j&#x…...

基于springboot的智能家居系统
TOC springboot198基于springboot的智能家居系统 研究背景与现状 时代的进步使人们的生活实现了部分自动化,由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现,都为人们生活的享受提供帮助。采用新型的自动化方式…...
【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(七)
本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》:python零基础入门学习 《python运维脚本》: python运维脚本实践 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8…...

C:每日一练:单身狗(2.0版本)
前言: 今天在刷题的时候突然看到一道题,疑似一位故题。仔细一看,欸!这不是就是单身狗的升级版吗?我想那必须再安排一篇,不过由于本篇文章与上一篇单身狗文章所涉及的知识点基本相同,所以还请大…...
打破接口壁垒:适配器模式让系统无缝对接
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间协同工作。主要用途是将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的对象可以一起工作。 一、适配器模式的组成 目标接口(…...
U-Boot 命令使用
U-Boot 是一种常用的引导加载程序,用于引导嵌入式系统。它提供了一系列命令以进行系统配置、引导操作和调试。 以下是一些常见的 U-Boot 命令及其用法: bootm:从指定的内存地址启动操作系统映像。 用法:bootm [addr] bootz&…...

谷歌的高级指令有哪些
今天会分享一些组合用法,这样就能节省许多时间可以放在跟进客户上面(本文只介绍谷歌的搜索指令,并无推广) part one 谷歌常用的搜索引擎指令: 1、Inurl,在网址中 2、Intext,在网页内容中 3、…...

Redis操作--RedisTemplate(一)介绍
一、介绍 1、简介 RedisTemplate 是 Spring Data Redis 提供的一个高级抽象,由 Spring 官方提供的方便操作 Redis 数据库的一个工具类,支持模板设计模式,使得操作 Redis 更加符合 Spring 的编程模型。还支持序列化机制,可以处理…...
GitLab环境搭建
GitLab环境搭建 一、环境搭建 1、更新系统软件包: sudo yum update2、安装docker sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install do…...

Socket编程TCP 基础
一.什么是Socket(套接字) 定义:就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程&#x…...
JAVA中的Iterator与ListIterator
Java中的Iterator类是Java集合框架中的一个重要接口,它用于遍历集合中的元素。Iterator提供了三个基本操作:检查是否有下一个元素、获取下一个元素以及移除元素。下面将详细介绍Iterator类及其使用方法,并提供相应的代码例子和中文注释。 一、…...

高校疫情防控web系统pf
TOC springboot365高校疫情防控web系统pf 第1章 绪论 1.1 课题背景 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。所以各行…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
js 设置3秒后执行
如何在JavaScript中延迟3秒执行操作 在JavaScript中,要设置一个操作在指定延迟后(例如3秒)执行,可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法,它接受两个参数: 要执行的函数&…...

动态规划-1035.不相交的线-力扣(LeetCode)
一、题目解析 光看题目要求和例图,感觉这题好麻烦,直线不能相交啊,每个数字只属于一条连线啊等等,但我们结合题目所给的信息和例图的内容,这不就是最长公共子序列吗?,我们把最长公共子序列连线起…...

基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)
注:文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件:STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...

Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...
用鸿蒙HarmonyOS5实现国际象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的国际象棋小游戏的完整实现代码,使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├── …...

Java设计模式:责任链模式
一、什么是责任链模式? 责任链模式(Chain of Responsibility Pattern) 是一种 行为型设计模式,它通过将请求沿着一条处理链传递,直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者,…...