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

C语言笔记27 •单链表介绍•

1.链表的概念及结构
        链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的。
2. 顺序表带来的问题
(1)中间/头部的插⼊删除,时间复杂度为O(N)
(2)增容需要申请新空间,拷⻉数据,释放旧空间。会有不⼩的消耗。
(3)增容⼀般是呈2倍的增⻓,势必会有⼀定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插⼊了5个数据,后⾯没有数据插⼊了,那么就浪费了95个数据空间。
  Ps:单链表的好处就是比顺序表结构简单,节省内存空间,随时申请内存随时使用。链表其实就是由节点组成的,节点中存储数据+指向下一节点的位置指针。
3.单链表实现头部、尾部、任意位置增加删除节点、销毁链表等操作
//SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SLTDataType;//定义节点中的数据类型
typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;//定义节点的结构体数据,以及下一结构体节点的(指针)地址,然后重命名为 SLTNodevoid SLTPrint(SLTNode* phead);//打印节点数据void SLTPushBack(SLTNode** pphead);//尾插void SLTPushFront(SLTNode** pphead);//头插void SLTPopBack(SLTNode** pphead);//尾删void SLTPopFront(SLTNode** pphead);//头删SLTNode* SLTFind(SLTNode* phead, SLTDataType x);//查找void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在指定位置之前插入数据void SLTInsertAfter(SLTNode* pos, SLTDataType x);//在指定位置之后插入数据void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos(指定位置)节点void SLTEraseAfter(SLTNode* pos);//删除pos之后的节点void SListDesTroy(SLTNode** pphead);//销毁链表
//SList.c#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"void SLTPrint(SLTNode* phead)//打印节点数据
{while (phead) //从第一个节点开始遍历,遇到NULL结束{printf("%d->", phead->data);phead=phead->next;}printf("NULL\n");
}SLTNode* SLTBuyNode(SLTDataType x)
{SLTNode* NEWNode = (SLTNode*)malloc(sizeof(SLTNode)); //内存分配时一定要注意写规范sizeof(SLTNode)=8不要写为sizeof(SLTNode*)=4, 大小就不一样肯定就会报错,分配了一个指向 SLTNode 的指针的内存,而不是分配一个 SLTNode 本身的内存。if (NEWNode == NULL){perror("malloc");exit(1);}NEWNode->data = x;NEWNode->next = NULL;return NEWNode;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x)//尾插
{assert(pphead);if (*pphead==NULL)//*pphead代表指向第一个节点的指针,如果是“空链表”进行尾插{*pphead = SLTBuyNode(x);}else             //如果是“非空链表”进行尾插{	SLTNode* ptail = *pphead;while (ptail->next) //从第一个节点开始遍历,判断指向下一个节点的指针是否为NULL   不能判断当前节点是否为空while (ptail) 进行结束循环,这不能代表下一节点是NULL{ptail = ptail->next;}//此时此刻ptail已经是尾节点了,ptail->next=NULLptail->next = SLTBuyNode(x); }
}
void SLTPushFront(SLTNode** pphead, SLTDataType x)//头插
{assert(pphead);// *pphead代表指向第一个节点的指针,如果是“空链表”进行头插SLTNode* pur = SLTBuyNode(x);pur->next = *pphead;*pphead = pur;
}void SLTPopBack(SLTNode** pphead)//尾删
{assert(pphead && *pphead);//链表不能为空//如果链表只有一个节点   //   ->优先级高于*所以要加上()if ((*pphead)->next == NULL)    {free(*pphead);*pphead = NULL;}//如果链表有多个节点else{SLTNode* prev  = *pphead; //保存末尾的上一个节点的地址,目的是等释放末尾节点后,使上一个节点的指向地址为NULL(prev->next= NULL;)SLTNode* ptail = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}free(ptail);ptail = NULL;prev->next= NULL;}
}void SLTPopFront(SLTNode** pphead)//头删
{assert(pphead && *pphead);//如果链表只有一个节点//if ((*pphead)->next == NULL)//{//	free(*pphead);//	*pphead = NULL;//}//else//如果链表有多个节点//{//	SLTNode* Nextnode = *pphead;//	*pphead = Nextnode->next;//}//通用//方案一//SLTNode* Nextnode = *pphead;//*pphead = Nextnode->next;//方案二SLTNode* Nextnode = (*pphead)->next;free(*pphead);*pphead = Nextnode;
}SLTNode* SLTFind(SLTNode* phead, SLTDataType x)//查找
{//assert(phead);SLTNode* pcur = phead;while (pcur){if (pcur->data == x){printf("找到了!\n");return pcur;//找到了}pcur = pcur->next;}return NULL;//没找到
}//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* pcur = *pphead;SLTNode* newnode = SLTBuyNode(x);//申请一个空间,存储要插入的节点if (pos == *pphead){SLTPushFront(pphead, x);//头插}else{while (pcur->next != pos){pcur = pcur->next;}//pcur->newnode->posnewnode->next = pos;pcur->next = newnode;}
}//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next= newnode;
}//删除pos(指定位置)节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);SLTNode* prev = *pphead;if (*pphead == pos)//执行头删{SLTPopFront(pphead);}else{while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* after = pos->next;pos->next = pos->next->next;free(after);after = NULL;
}//销毁链表
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* Nextnode = pcur->next;free(pcur);pcur = Nextnode;}*pphead = NULL;
}

//SeqList-test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"void SList_test()
{//给节点里创建数据SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));node1->data = 1;SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));node2->data = 2;SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));node3->data = 3;SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));//内存分配时一定要注意写规范sizeof(SLTNode)=8不要写为sizeof(SLTNode*)=4, 大小就不一样肯定 就会报错,分配了一个指向 SLTNode 的指针的内存,而不是分配一个 SLTNode 本身的内存。node4->data = 4;//给节点之间建立联系node1->next = node2;node2->next = node3;node3->next = node4;node4->next = NULL;//调用链表打印SLTNode* plist = node1;//SLTNode* plist = NULL; //SLTPushBack(NULL, 5);//尾插//SLTPrint(plist);//打印节点数据SLTPushBack(&plist, 5);//尾插SLTPrint(plist);//打印节点数据SLTPushFront(&plist, 0);//头插SLTPrint(plist);//打印节点数据SLTPopBack(&plist);//尾删SLTPrint(plist);//打印节点数据SLTPopFront(&plist);//头删SLTPrint(plist);//打印节点数据}void SList_test1()
{SLTNode* plist = NULL; SLTPushBack(&plist, 1);//尾插SLTPrint(plist);//打印节点数据SLTPushBack(&plist, 2);//尾插SLTPrint(plist);//打印节点数据SLTPushBack(&plist, 3);//尾插SLTPrint(plist);//打印节点数据//SLTPushFront(&plist, 0);//头插//SLTPrint(plist);//打印节点数据//SLTPopBack(&plist);//尾删//SLTPrint(plist);//打印节点数据//SLTPopFront(&plist);//头删//SLTPrint(plist);//打印节点数据//SLTFind(plist,1);//查找//SLTFind(plist, 3);//查找SLTNode* find=SLTFind(plist, 3);//查找位置SLTInsert(&plist, find, 0);//在指定位置之前插入数据SLTPrint(plist);//打印节点数据 1->2->0->3->NULLfind = SLTFind(plist, 2);//查找位置SLTInsertAfter(find, 4);//在指定位置之后插入数据SLTPrint(plist);//打印节点数据  1->2->4->0->3->NULLfind = SLTFind(plist, 3);//查找位置SLTErase(&plist, find);//删除pos(指定位置)节点SLTPrint(plist);//打印节点数据  1->2->4->0->NULLfind = SLTFind(plist, 4);//查找位置SLTEraseAfter(find);SLTPrint(plist);//打印节点数据  1->2->4->NULLSListDesTroy(&plist);//销毁链表SLTPrint(plist);//打印节点数据//SLTPushBack(&plist, 1);//尾插//SLTPrint(plist);//打印节点数据
}int main()
{//SList_test();SList_test1();//printf("%zd %zd", sizeof(SLTNode), sizeof(SLTNode*)); //8, 4return 0;
}

相关文章:

C语言笔记27 •单链表介绍•

1.链表的概念及结构 链表是⼀种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表 中的指针链接次序实现的。 2. 顺序表带来的问题 (1)中间/头部的插⼊删除&#xff0c;时间复杂度为O(N) (2)增容需要申请新空间&#xff0c;拷⻉数据&#xff…...

C++编程(五)单例模式 友元

文章目录 一、单例模式&#xff08;一&#xff09;概念&#xff08;二&#xff09;实现方式1. 饿汉式2. 懒汉式 二、友元&#xff08;一&#xff09;概念&#xff08;二&#xff09;友元函数1.概念2.语法格式3. 使用示例访问静态成员变量访问非静态成员变量 &#xff08;三&…...

012-GeoGebra基础篇-构造圆的切线

前边文章对于基础内容已经悉数覆盖了&#xff0c;这一篇我就不放具体的细节&#xff0c;若有需要可以复刻一下 目录 一、成品展示二、算式内容三、正确性检查五、文章最后 一、成品展示 二、算式内容 A(0,0) B(3,0) c: Circle(A,B) C(5,4) sSegment(A,C) DMidpoint(s) d: Circ…...

数据结构速成--查找

由于是速成专题&#xff0c;因此内容不会十分全面&#xff0c;只会涵盖考试重点&#xff0c;各学校课程要求不同 &#xff0c;大家可以按照考纲复习&#xff0c;不全面的内容&#xff0c;可以看一下小编主页数据结构初阶的内容&#xff0c;找到对应专题详细学习一下。 目录 …...

SpringMVC的基本使用

SpringMVC简介 SpringMVC是Spring提供的一套建立在Servlet基础上&#xff0c;基于MVC模式的web解决方案 SpringMVC核心组件 DispatcherServlet&#xff1a;前置控制器&#xff0c;来自客户端的所有请求都经由DispatcherServlet进行处理和分发Handler&#xff1a;处理器&…...

【PYG】Cora数据集分类任务计算损失,cross_entropy为什么不能直接替换成mse_loss

cross_entropy计算误差方式&#xff0c;输入向量z为[1,2,3]&#xff0c;预测y为[1]&#xff0c;选择数为2&#xff0c;计算出一大坨e的式子为3.405&#xff0c;再用-23.405计算得到1.405MSE计算误差方式&#xff0c;输入z为[1,2,3]&#xff0c;预测向量应该是[1,0,0]&#xff0…...

MyBatis-plus这么好用,不允许还有人不会

你好呀&#xff0c;我是 javapub. 做 Java 的同学都会用到的三件套&#xff0c;Spring、SpringMV、MyBatis。但是由于使用起来配置较多&#xff0c;依赖冲突频发。所有&#xff0c;各路大佬又在这上边做了包装&#xff0c;像我们常用的 SpringBoot、MyBatisPlus。 基于当前要…...

Linux驱动开发实战宝典:设备模型、模块编程、I2C/SPI/USB外设精讲

摘要: 本文将带你走进 Linux 驱动开发的世界,从设备驱动模型、内核模块开发基础开始,逐步深入 I2C、SPI、USB 等常用外设的驱动编写,结合实际案例,助你掌握 Linux 驱动开发技能。 关键词: Linux 驱动,设备驱动模型,内核模块,I2C,SPI,USB 一、Linux 设备驱动模型 Li…...

安全技术和防火墙

1、安全技术 1.1入侵检测系统 特点是不阻断网络访问&#xff0c;主要提供报警和事后监督。不主动介入&#xff0c;默默的看着你&#xff08;类似于监控&#xff09; 1.2入侵防御系统 透明模式工作&#xff0c; 数据包&#xff0c;网络监控&#xff0c;服务攻击&#xff0c;…...

Webpack: 开发 PWA、Node、Electron 应用

概述 毋庸置疑&#xff0c;对前端开发者而言&#xff0c;当下正是一个日升月恒的美好时代&#xff01;在久远的过去&#xff0c;Web 页面的开发技术链条非常原始而粗糙&#xff0c;那时候的 JavaScript 更多用来点缀 Web 页面交互而不是用来构建一个完整的应用。直到 2009年5月…...

python处理txt文件, 如果第一列和第二列的值在连续的行中重复,则只保留一行

处理txt文件, 如果第一列和第二列的值在连续的行中重复,则只保留一个实例,使用Python的内置函数来读取文件,并逐行检查和处理数据。 一个txt文件,里面的数据是893.554382324,-119.955825806,0.0299997832626,-0.133618548512,28.1155740884,112.876833236,46.7922,19.62582…...

C++17中引入了什么新的重要特性

C17是C标准的一个重要版本&#xff0c;它在语言核心和标准库中引入了许多新特性和改进&#xff0c;使得C编程更加现代化和高效。以下是C17中引入的一些重要新特性&#xff1a; 语言核心新特性 结构化绑定&#xff08;Structured Bindings&#xff09;&#xff1a; 结构化绑定…...

Andrej Karpathy提出未来计算机2.0构想: 完全由神经网络驱动!网友炸锅了

昨天凌晨&#xff0c;知名人工智能专家、OpenAI的联合创始人Andrej Karpathy提出了一个革命性的未来计算机的构想&#xff1a;完全由神经网络驱动的计算机&#xff0c;不再依赖传统的软件代码。 嗯&#xff0c;这是什么意思&#xff1f;全部原生LLM硬件设备的意思吗&#xff1f…...

用国内镜像安装docker 和 docker-compose (ubuntu)

替代方案&#xff0c;改用国内的镜像站(网易镜像&#xff09; 1.清除旧版本&#xff08;可选操作&#xff09; for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do apt-get remove $pkg; done 2.安装docker apt-get update 首先安装依赖 apt-g…...

Linux多线程【线程互斥】

文章目录 Linux线程互斥进程线程间的互斥相关背景概念互斥量mutex模拟抢票代码 互斥量的接口初始化互斥量销毁互斥量互斥量加锁和解锁改进模拟抢票代码&#xff08;加锁&#xff09;小结对锁封装 lockGuard.hpp 互斥量实现原理探究可重入VS线程安全概念常见的线程不安全的情况常…...

os实训课程模拟考试(大题复习)

目录 一、Linux操作系统 &#xff08;1&#xff09;第1关&#xff1a;Linux初体验 &#xff08;2&#xff09;第2关&#xff1a;Linux常用命令 &#xff08;3&#xff09;第3关&#xff1a;Linux 查询命令帮助语句 二、Linux之进程管理—&#xff08;重点&#xff09; &…...

QT/QML国际化:中英文界面切换显示(cmake方式使用)

目录 前言 实现步骤 1. 准备翻译文件 2. 翻译字符串 3.设置应用程序语言 cmake 构建方式 示例代码 总结 1. 使用 file(GLOB ...) 2. 引入其他资源文件 再次生成翻译文件 5. 手动更新和生成.qm文件 其他资源 前言 在当今全球化的软件开发环境中&#xff0c;应用程…...

设计模式在Java项目中的实际应用

设计模式在Java项目中的实际应用 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 引言 设计模式是软件开发中重要的思想工具&#xff0c;它提供了解决特定问题…...

js制作随机四位数验证码图片

<div class"lable lable2"><div class"l"><span>*</span>验证码</div><div class"r"><input type"number" name"vercode" placeholder"请输入验证码"></div>&l…...

[开源软件] 支持链接汇总

“Common rules: 1- If the repo is on github, the support/bug link is also on the github with issues”" label; 2- Could ask questions by email list;" 3rd party software support link Note gcc https://gcc.gnu.org openssh https://bugzilla.mindrot.o…...

【Midjourney商业设计变现指南】:20个已验证的高转化落地场景与客户签约话术库

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Midjourney商业设计变现的核心逻辑与验证框架 Midjourney 不是单纯的图像生成工具&#xff0c;而是连接创意需求、交付效率与商业闭环的智能设计协作者。其核心变现逻辑建立在“提示词工程 品牌资产沉…...

0-π量子比特设计原理与拓扑保护机制

1. 0-π量子比特的物理基础与设计挑战 在超导量子计算领域&#xff0c;0-π量子比特因其独特的拓扑保护特性而备受关注。这种量子比特的设计基于两个关键自由度&#xff1a;θ和φ相位变量&#xff0c;分别对应电路中的两个正交振荡模式。与传统transmon比特相比&#xff0c;0-…...

高精度直流功率监测模块INA23x:硬件解析与嵌入式应用实战

1. 项目概述&#xff1a;为什么你需要一个专业的直流功率监测模块&#xff1f;在嵌入式开发、机器人、无人机或者任何需要精确电源管理的项目中&#xff0c;你肯定遇到过这样的问题&#xff1a;我的设备到底耗电多少&#xff1f;电池还能撑多久&#xff1f;这个电机堵转时的电流…...

智能护理床控制板开发:从单片机到机电一体化的实战解析

1. 项目概述&#xff1a;从手动到智能&#xff0c;一款控制板如何重塑护理体验在康复护理和老年照护领域&#xff0c;一张床不仅仅是休息的地方&#xff0c;它更是使用者维持尊严、促进康复、保障安全的重要工具。传统的护理床依赖手动摇杆&#xff0c;每一次姿势调整都需要护理…...

3步搞定Axure中文汉化:让专业原型设计工具说中文

3步搞定Axure中文汉化&#xff1a;让专业原型设计工具说中文 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 你是否在使用Axure …...

别再一张张手动改了!用Python脚本批量解密微信PC版dat图片(附完整代码)

用Python自动化解密微信PC版dat图片的完整指南 微信PC版默认会将接收的图片保存为加密的dat文件格式&#xff0c;这些文件无法直接查看或使用。传统方法需要手动一张张转换&#xff0c;效率极低。本文将详细介绍如何用Python编写脚本&#xff0c;实现dat图片的批量自动解密&am…...

隔着包装也能读、2m/s不串读:东集UF40如何应对管制药厂的RFID“极限大考”?

提到RFID固定式读写器&#xff0c;很多人的第一印象是仓库、货架与托盘。但在一些关乎生命安全的领域&#xff0c;RFID技术正面临着更严苛的考验。这一次&#xff0c;我们走进管制药厂——一个对精准追溯要求达到极致、不容任何差错的场景。核心痛点&#xff1a;一盒十瓶&#…...

遗传算法混合动力汽车控制策略【附代码】

✨ 长期致力于混合动力汽车、能量管理策略、模糊控制、遗传算法研究工作&#xff0c;擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;点击《获取方式》 &#xff08;1&#xff09;多目标分层编码与种群初始化策略&…...

别再死记硬背DQN了!用游戏开发者的视角,图解Replay Buffer、LSTM等6大改进的实战意义

游戏开发者视角&#xff1a;图解DQN六大改进的实战意义 在游戏AI开发中&#xff0c;强化学习正逐渐成为构建智能对手和NPC的核心工具。但传统DQN算法在实际应用中常常遇到各种瓶颈——智能体学习效率低下、在复杂环境中表现不稳定、难以处理部分可观测状态等问题。这些问题恰恰…...

抖音无水印批量下载终极指南:3分钟学会免费下载视频、音乐和直播

抖音无水印批量下载终极指南&#xff1a;3分钟学会免费下载视频、音乐和直播 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fall…...