数据结构——链表(单链表)

大家好,又是我(小锋),今天给大家带了一个比较有挑战的章节(链表),但是不用担心,小锋会陪大家一起度过。

顺序表的思考与问题

1. 中间/头部的插入删除,时间复杂度为O(N)
我们在进行一些插入删除操作时我们会先内存覆盖然后再进行操作,覆盖内存的时间复杂度为O(N)。
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
当我们进行扩容时我们是不是要用realloc函数,而realloc函数再扩容时分为异地扩容,和原地扩容,当我们异地扩容时又有一系列的操作这又加大了消耗。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到
200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
我们增加容量后可能用不完,这就会造成空间的浪费,以及顺序表的空间是连续的我们要释放就必须全部释放。
那我们今天讲到链表就不会出现上面的问题,但也不是说链表就没有缺点,不论是顺序表还是链表都有优缺点,重点在于我们怎么运用。

链表

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
我们这节主要讲解单链表
这个就是链表的逻辑结构了,一个节点中有指向下一个节点的指针,这样走下去最后一个节点中放的是空指针NULL,像链条一样一环扣一环。
我给大家画一个物理结构方便大家理解
我们可以形象看出链表的基本结构
那我们来创建一个链表
我们先来实现一个打印链表内容的函数

单链表打印

//链表输出void LBexport(LBbiao* att) {assert(att);LBbiao* ps = att;while (ps!= NULL) {printf("%d->", ps->SZ);ps = ps->next;}printf("NULL\n");}

这里大家可以画图一步一步的理一下理解会更加深刻主要注意循环的判断条件。

我们下面来实现一个插入函数

单链表头插数据

我们想一想在链表的头部插入数据我们只需要开辟一个链表空间mon然后另它的next指向当前链表的表头的地址,并将mon的地址交给表头的指针是不是就可以插入数据并且将链表连接起来了?

大家可以看看大致原理如图
我们还要注意要进行断言防止出现错误
//链表头插数据void LBcutin(LBbiao** att,CMMlet n) {assert(att);LBbiao* pt = LBopen();if (*att == NULL) {*att = pt;}else {pt->next = *att;*att = pt;}pt->SZ = n;}
这里开辟一个新的链表空间我们还会用到所有我们用一个函数来实现
//开辟链表LBbiao* LBopen() {LBbiao* mon = (LBbiao*)malloc(sizeof(CMMlet) + sizeof(LBbiao*));if (mon == NULL) {printf("开辟失败:%s",strerror(errno));return NULL;}mon->next = NULL;mon->SZ = 0;return mon;}
我们这里可以用老方法,分装一个函数来验证

单链表头删数据

还是我们用图来演示

//链表头删数据void LBdelete(LBbiao**att) {assert(*att != NULL);assert(att != NULL);//断言LBbiao* ps = *att;*att = ps->next;ps->next = NULL;free(ps);}

我们验证试试

单链表尾删数据

我们还是画图演示原理

我们可以看见尾删数据直接将倒数第二个节点的next为空就行了,当然我们还要断言一些情况

并且我们还要分情况当链表只有一个节点时该怎么删。

//链表尾删数据void LBweishan(LBbiao*att) {assert(att != NULL);//断言LBbiao* ps = att;while (ps->next->next != NULL) {ps = ps->next;}free(ps->next);ps->next = NULL;}

单链表尾插数据

老规矩画图理解

我们通过图可以看出尾插数据要开辟一个新的节点然后让原链表的最后一个节点的next指向新开辟出来的节点并将新开辟的节点的next为空。同样我们要分情况讨论

//链表尾插数据void LBweicha(LBbiao** att,CMMlet n) {LBbiao* ps = *att;LBbiao* pt = LBopen();if (ps == NULL) {*att = pt;}else {while (ps->next != NULL) {ps = ps->next;}ps->next = pt;}pt->SZ = n;}

单链表查找

我们可以直接遍历链表如果遇到我们就返回该数据的节点地址,如果没找到我们返回NULL。

//链表查找LBbiao* LBchazhao(LBbiao* att, CMMlet n) {assert(att);LBbiao* ps = att;while (ps != NULL) {if (ps->SZ == n) {return ps;break;}ps = ps->next;}return NULL;}

我们可以测试一下

单链表在pos位置之后插入x

与头插类似我们主要注意的是要不要分情况讨论,以及断言的内容,具体插入的过程我们大家可以自己画图试试

接下来我们来实现一下这个函数

//链表在pos位置后插入xvoid LBporcr(LBbiao* pos, CMMlet x) {assert(pos);LBbiao* ps = pos;LBbiao* pt = LBopen();if (pos->next == NULL) {//相当于尾插数据LBweicha(&pos, x);}else {//一般情况pt->next=ps->next;ps->next = pt;pt->SZ = x;}}

验证试试

单链表删除pos位置之后的值

我们还是用图说话

分析后我们发现我们只需要将pos位置的next指向pos->next->next就ok了,最后还要注意一下特殊情况以及断言

//链表在pos位置后删除xvoid LBpossc(LBbiao* pos) {assert(pos&&pos->next!=NULL);if (pos->next->next == NULL) {//相当于尾删free(pos->next);pos->next = NULL;}else {LBbiao* ps = pos->next;pos->next = pos->next->next;ps->next = NULL;free(ps->next);}}

我们可以测试一下

我们的单链表就讲解完了是不是畅快淋漓呢?

这是我们本节的所有代码大家可以自己试试

# define _CRT_SECURE_NO_WARNINGS 1
# include<stdio.h>
# include<assert.h>
# include<string.h>
# include<errno.h>
# include<stdlib.h>//类型重命名
//方便后期修改
typedef struct LBbiao LBbiao;
typedef int CMMlet;
//链表创建struct LBbiao{CMMlet SZ;//链表存储的数据struct LBbiao* next;//指向下一个节点};//开辟链表LBbiao* LBopen() {LBbiao* mon = (LBbiao*)malloc(sizeof(CMMlet) + sizeof(LBbiao*));if (mon == NULL) {printf("开辟失败:%s",strerror(errno));return NULL;}mon->next = NULL;mon->SZ = 0;return mon;}//链表输出void LBexport(LBbiao* att) {assert(att);LBbiao* ps = att;while (ps!= NULL) {printf("%d->", ps->SZ);ps = ps->next;}printf("NULL\n");}//链表头插数据void LBcutin(LBbiao** att,CMMlet n) {assert(att);LBbiao* pt = LBopen();if (*att == NULL) {*att = pt;}else {pt->next = *att;*att = pt;}pt->SZ = n;}//链表头删数据void LBdelete(LBbiao**att) {assert(*att != NULL);assert(att != NULL);//断言LBbiao* ps = *att;*att = ps->next;ps->next = NULL;free(ps);}//链表尾删数据void LBweishan(LBbiao**att) {assert(att != NULL);//断言assert(*att != NULL);LBbiao* ps = *att;if (ps->next == NULL) {*att = NULL;free(ps);}else {while (ps->next->next != NULL) {ps = ps->next;}free(ps->next);ps->next = NULL;}}//链表尾插数据void LBweicha(LBbiao** att,CMMlet n) {LBbiao* ps = *att;LBbiao* pt = LBopen();if (ps == NULL) {*att = pt;}else {while (ps->next != NULL) {ps = ps->next;}ps->next = pt;}pt->SZ = n;}//链表查找LBbiao* LBchazhao(LBbiao* att, CMMlet n) {assert(att);LBbiao* ps = att;while (ps != NULL) {if (ps->SZ == n) {return ps;break;}ps = ps->next;}return NULL;}//链表在pos位置后插入xvoid LBporcr(LBbiao* pos, CMMlet x) {assert(pos);LBbiao* ps = pos;LBbiao* pt = LBopen();if (pos->next == NULL) {//相当于尾插数据LBweicha(&pos, x);}else {//一般情况pt->next=ps->next;ps->next = pt;pt->SZ = x;}}//链表在pos位置后删除xvoid LBpossc(LBbiao* pos) {assert(pos&&pos->next!=NULL);if (pos->next->next == NULL) {//相当于尾删free(pos->next);pos->next = NULL;}else {LBbiao* ps = pos->next;pos->next = pos->next->next;ps->next = NULL;free(ps->next);}}//测试链表1void ceshi1() {LBbiao* arr = NULL;LBweicha(&arr, 1);LBweicha(&arr, 2);LBweicha(&arr, 3);LBweicha(&arr, 4);LBexport(arr);LBporcr(arr, 0);LBexport(arr);LBpossc(arr);LBexport(arr);}int main() {ceshi1();return 0;}

  以上就是全部内容了,如果有错误或者不足的地方欢迎大家给予建议。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/773221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【python】flask模板渲染引擎Jinja2,通过后端数据渲染前端页面

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Spring Cloud 八:微服务架构中的数据管理

Spring Cloud 一&#xff1a;Spring Cloud 简介 Spring Cloud 二&#xff1a;核心组件解析 Spring Cloud 三&#xff1a;API网关深入探索与实战应用 Spring Cloud 四&#xff1a;微服务治理与安全 Spring Cloud 五&#xff1a;Spring Cloud与持续集成/持续部署&#xff08;CI/C…

Eladmin-jpa基于SpringBoot和Vue的前后端分离后台管理系统​

在当今快速发展的软件开发领域&#xff0c;前后端分离的架构模式已经成为主流。这种架构模式不仅可以提高开发效率&#xff0c;还能使系统更加易于维护和扩展。Eladmin-jpa是一个基于Spring Boot 2.6.4、Spring Boot Jpa、JWT、Spring Security、Redis和Vue的前后端分离的后台管…

JS等比压缩图片方法

AI给出来的答案&#xff0c;AI真的能改变世界&#xff0c;以后程序员这个职业真的有可能不存在了。 function compressImage(image, callback) {// 创建一个 canvas 元素const canvas document.createElement(canvas);canvas.width 48;canvas.height 48;// 获取 canvas 的绘…

[WTL/Win32]_[初级]_[如何设置ListView的列宽不出现水平滚动条]

场景 开发WTL/Win32的程序时&#xff0c;经常会用到表格控件CListViewCtrl。这个控件需要设置列的宽度&#xff0c;当用完100%的宽度来平均分配给列宽时&#xff0c;一加载数据多&#xff0c;就会出现垂直滚动条后&#xff0c;水平滚动条也会同时出现的问题。怎么设置才能让水…

Stable Diffusion 本地部署教程

Stable Diffusion是一种用于构建和部署机器学习模型的开源工具。以下是在本地环境中部署 Stable Diffusion 的基本步骤: 步骤 1: 准备环境 确保你的系统中已经安装了以下软件和工具: Python(建议使用 Python 3.x)pip(Python 包管理工具)Docker(可选,用于容器化部署)…

【研发日记】Matlab/Simulink开箱报告(十)——Signal Routing模块模块

文章目录 前言 Signal Routing模块 虚拟模块和虚拟信号 Mux和Demux Vector Concatenate和Selector Bus Creator和Bus Selector 分析和应用 总结 前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;五&#xff09;——S-Fuction模块(C MEX S-Fun…

三、 mariadb数据库用户管理

1)查询有哪些用户 MariaDB> select user,host from mysql.user; ----------------- | user | host | ----------------- | root | 127.0.0.1 | | root | ::1 | | | localhost | | root | localhost | | | oldboy | | root | oldboy | ---------…

单链表专题(上)(顺序表链表线性表)

在开始之前思考一个顺序表的问题 1. 中间/头部的插⼊删除&#xff0c;时间 复杂度为O(N) 2. 增容需要申请新空间&#xff0c;拷⻉数据&#xff0c;释放旧空间。会有不⼩的消耗。 3. 增容⼀般是呈2倍的增⻓&#xff0c;势必会有⼀定的空间浪费。例如当前容量为100&#xff0c;…

类模板分文件编写

问题&#xff1a; 类模板中成员函数创建时机是在调用阶段&#xff0c;导致分文件编写时链接不到 解决&#xff1a; 解决方式1&#xff1a;直接包含.cpp源文件 解决方式2&#xff1a;将声明和实现写到同一个文件中&#xff0c;并更改后缀名为.hpp&#xff0c;hpp是约定的名称…

订单系统-RPC快速入门

RPC快速入门 概述 关于rpc&#xff0c;只需要知道他是一种协议&#xff0c;项目之间能够远程调用函数。 快速入门 我们前边下载好的两个包&#xff0c;在idea中打开之后&#xff0c;我们创建这么几个文件夹。 至于是干什么的&#xff0c;以后细说。创建好之后我们在produc…

【Java 面试题】面向对象和面向过程的区别

面向对象和面向过程的区别&#xff1f; 面向对象编程&#xff08;OOP&#xff09;和面向过程编程&#xff08;POP&#xff09;是两种不同的编程范式&#xff0c;它们之间有一些重要的区别&#xff1a; 思想方式&#xff1a; 面向对象编程&#xff1a;将问题看作是一组对象之间…

【OpenStack】创建并部署自己的Web服务器和应用

【OpenStack】创建并部署自己的Web服务器和应用 目录 【OpenStack】创建并部署自己的Web服务器和应用云服务的工作原理查看Swift Python SDK连接发送请求使用其他SDK和其他语言运行项目克隆存储库安装项目依赖项定义环境配置启动服务器推荐超级课程: Docker快速入门到精通

C语言如何定义有参函教?

一、问题 有参函数是函数的重点部分&#xff0c;那么如何定义有参函数呢&#xff1f; 二、解答 有参函数定义的⼀般形式如下。 类型声明符 函数名&#xff08;形式参数列表&#xff09; {声明部分;语句; } 在形参列表中给出的参数称为形式参数&#xff0c;它们可以是各种类型…

从零开始搭建游戏服务器 第七节 创建GameServer

目录 前言正文创建GameServer模块修改配置创建NettyClient连接到登录服登录服修改创建协议游戏服注册到登录服 总结 前言 上一节我们使用自定义注解反射简化了协议解包和逻辑处理分发流程。 那么到了这里登录服登录服的架构已经搭建的差不多了&#xff0c;一些比较简单的、并发…

使用 Outline 构建 企业 or 个人 知识库面临的问题

前不久&#xff0c;我写了一篇文章&#xff0c;介绍《如何在本地部署安装 Outline》&#xff0c;我之所以写这篇文章&#xff0c;主要原因是我最近需要做一个项目&#xff0c;使用 Outline 来构建一个公司级知识库。所以我需要在本地先搭建一个&#xff0c;来撰写一些前期的文档…

【环境配置】Ubuntu MySQL 8.0.28 安装并允许外部客户端连接

文章目录 MySQL 安装步骤配置 MySQL Server 允许外部连接 MySQL 安装步骤 步骤一&#xff1a;在 MySQL 官网找到 apt 仓库&#xff0c;下载最新的仓库 点击 Download&#xff1a; 输入如下命令&#xff1a; sudo wget -c https://dev.mysql.com/get/mysql-apt-config_0.8…

2014年认证杯SPSSPRO杯数学建模A题(第一阶段)轮胎的花纹全过程文档及程序

2014年认证杯SPSSPRO杯数学建模 A题 轮胎的花纹 原题再现&#xff1a; 轮胎被广泛使用在多种陆地交通工具上。根据性能的需要&#xff0c;轮胎表面常会加工出不同形状的花纹。在设计轮胎时&#xff0c;往往要针对其使用环境&#xff0c;设计出相应的花纹形状。   第一阶段问…

JVM(三)——字节码技术

三、字节码技术 1、类文件结构 一个简单的 HelloWorld.java package com.mysite.jvm.t5; // HelloWorld 示例 public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");} }执行 javac -parameters -d . HellowWorld.…

Selenium 自动化 —— 实战篇之自动登录163邮箱

Selenium 自动化专栏系列文章 &#xff08;一&#xff09;入门和 Hello World 实例&#xff08;二&#xff09;使用WebDriverManager自动下载驱动&#xff08;三&#xff09;Selenium IDE录制、回放、导出Java源码&#xff08;四&#xff09;浏览器窗口操作&#xff08;五&…