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

【数据结构篇】~单链表(附源码)

【数据结构篇】~链表

  • 链表前言
  • 链表的实现
    • 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.源文件 链表前言 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 1、链式机构在逻辑上是连续的&#xff0c;在物理结构上不一定连续​ 2、结点一般是从…...

旋转图像(LeetCode)

题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 解题 def rotate(matrix):n len(matrix)# 矩阵转置for i in range(n):for…...

入门 - vue中v-model的实现原理和完整用法详解

v-model介绍 v-model是vue的双向绑定的指令&#xff0c;能将页面上控件输入的值同步更新到相关绑定的data属性&#xff0c;也会在更新data绑定属性时候&#xff0c;更新页面上输入控件的值。在view层&#xff0c;model层相互需要数据交互&#xff0c;即可使用v-model。 双向绑…...

【区块链+金融服务】港融区域股权服务平台 | FISCO BCOS应用案例

中国证监会在 2020 年启动了区块链建设试点工作&#xff0c;提出建设基于区块链的场外市场登记系统和交易报告库&#xff0c;利 用区块链去中心化、不易篡改、安全稳定等技术特点&#xff0c;构建区域性股权市场数字化信任机制&#xff0c;为区域性股权市场 提供基础支撑设施。…...

Nginx反向代理和前后端分离项目打包部署

Nginx反向代理 Nginx的定位&#xff1a;主要用于做反向代理&#xff0c;一般都是用它来做前端页面的服务器&#xff0c;动态资源代理到后端服务器。这样做的好处是可以避免跨域请求带来的不便。 使用Nginx主要是对Nginx中的nginx.conf文件进行配置&#xff1a; 虚拟主机配置…...

Spring 中ApplicationContext

ApplicationContext 是 Spring 框架中最重要的接口之一&#xff0c;用于提供 Spring IoC 容器的功能。它是一个比 BeanFactory 更高级的容器&#xff0c;负责管理 Spring bean 的生命周期&#xff0c;同时提供对各种企业服务的集成&#xff0c;例如事件传播、国际化、弱引用等。…...

python之时间 datetime、date、time、timedelta、dateutil

在 Python 中&#xff0c;处理日期和时间的常用库是 datetime。此外&#xff0c;还有一些第三方库如 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子集搜索与评价 特征&#xff1a;描述物…...

LeetCode-day43-3137. K 周期字符串需要的最少操作次数

LeetCode-day43-3137. K 周期字符串需要的最少操作次数 题目描述示例示例1&#xff1a;示例2&#xff1a; 思路代码 题目描述 给你一个长度为 n 的字符串 word 和一个整数 k &#xff0c;其中 k 是 n 的因数。 在一次操作中&#xff0c;你可以选择任意两个下标 i 和 j&#x…...

基于springboot的智能家居系统

TOC springboot198基于springboot的智能家居系统 研究背景与现状 时代的进步使人们的生活实现了部分自动化&#xff0c;由最初的全手动办公已转向手动自动相结合的方式。比如各种办公系统、智能电子电器的出现&#xff0c;都为人们生活的享受提供帮助。采用新型的自动化方式…...

【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(七)

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…...

C:每日一练:单身狗(2.0版本)

前言&#xff1a; 今天在刷题的时候突然看到一道题&#xff0c;疑似一位故题。仔细一看&#xff0c;欸&#xff01;这不是就是单身狗的升级版吗&#xff1f;我想那必须再安排一篇&#xff0c;不过由于本篇文章与上一篇单身狗文章所涉及的知识点基本相同&#xff0c;所以还请大…...

打破接口壁垒:适配器模式让系统无缝对接

适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许不兼容的接口之间协同工作。主要用途是将一个类的接口转换成客户期望的另一个接口&#xff0c;使得原本接口不兼容的对象可以一起工作。 一、适配器模式的组成 目标接口&#xff08…...

U-Boot 命令使用

U-Boot 是一种常用的引导加载程序&#xff0c;用于引导嵌入式系统。它提供了一系列命令以进行系统配置、引导操作和调试。 以下是一些常见的 U-Boot 命令及其用法&#xff1a; bootm&#xff1a;从指定的内存地址启动操作系统映像。 用法&#xff1a;bootm [addr] bootz&…...

谷歌的高级指令有哪些

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

Redis操作--RedisTemplate(一)介绍

一、介绍 1、简介 RedisTemplate 是 Spring Data Redis 提供的一个高级抽象&#xff0c;由 Spring 官方提供的方便操作 Redis 数据库的一个工具类&#xff0c;支持模板设计模式&#xff0c;使得操作 Redis 更加符合 Spring 的编程模型。还支持序列化机制&#xff0c;可以处理…...

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(套接字&#xff09; 定义&#xff1a;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲&#xff0c;套接字上联应用进程&#x…...

JAVA中的Iterator与ListIterator

Java中的Iterator类是Java集合框架中的一个重要接口&#xff0c;它用于遍历集合中的元素。Iterator提供了三个基本操作&#xff1a;检查是否有下一个元素、获取下一个元素以及移除元素。下面将详细介绍Iterator类及其使用方法&#xff0c;并提供相应的代码例子和中文注释。 一、…...

高校疫情防控web系统pf

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

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...