数据结构(四)顺序表与链表的深层次讲解

我们在数据结构(二),对链表和顺序表已经讲解过了。但很多同学表示有点晦涩难懂那我就出一篇深层次讲解,一步一步来带领大家学习。

我们从头(数据结构)开始完整的来为大家讲解,大家好好看好好学。定有收获

1.数据结构相关概念

1.1、什么是数据结构?

数据结构是由“数据”和“结构”两词组合⽽来。
什么是数据?

常⻅的数值1、2、3、4.....、教务系统⾥保存的⽤⼾信息(姓名、性别、年龄、学历等等)、⽹⻚⾥⾁眼可以看到的信息(⽂字、图⽚、视频等等),这些都是数据
什么是结构?
当我们想要使⽤⼤量使⽤同⼀类型的数据时,通过⼿动定义⼤量的独⽴的变量对于程序来说,可读性⾮常差,我们可以借助数组这样的数据结构将⼤量的数据组织在⼀起,结构也可以理解为组织数据的⽅式。
想要找到草原上名叫“咩咩”的⽺很难,但是从⽺圈⾥找到1号⽺就很简单,⽺圈这样的结构有效将
⽺群组织起来。
概念:数据结构是计算机存储、组织数据的⽅式。数据结构是指相互之间存在⼀种或多种特定关系
的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么⽅式构成,以及数据元素之间呈现的结构。
总结:
1)能够存储数据(如顺序表、链表等结构)?
2)存储的数据能够⽅便查找?
2、为什么需要数据结构?


如图中所⽰,不借助排队的⽅式来管理客⼾,会导致客⼾就餐感受差、等餐时间⻓、餐厅营业混乱等情况。同理,程序中如果不对数据进⾏管理,可能会导致数据丢失、操作数据困难、野指针等情况。
通过数据结构,能够有效将数据组织和管理在⼀起。按照我们的⽅式任意对数据进⾏增删改查等操
作。最基础的数据结构:数组。


【思考】有了数组,为什么还要学习其他的数据结构?
假定数组有10个空间,已经使⽤了5个,向数组中插⼊数据步骤:?
求数组的⻓度,求数组的有效数据个数,向下标为数据有效个数的位置插⼊数据(注意:这⾥是
否要判断数组是否满了,满了还能继续插⼊吗).....?
假设数据量⾮常庞⼤,频繁的获取数组有效数据个数会影响程序执⾏效率。
结论:最基础的数据结构能够提供的操作已经不能完全满⾜复杂算法实现。


2.顺序表

2.1、顺序表的概念及结构?

2.1.1线性表

线性表( linear list )是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中⼴泛使
 ⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...
 线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。
案例:蔬菜分为绿叶类、⽠类、菌菇类。线性表指的是具有部分相同特性的⼀类数据结构的集合
如何理解逻辑结构和物理结构?

2.1.2顺序表分类

顺序表和数组的区别:

顺序表的底层结构是数组,对数组的封装,实现了常⽤的增删改查等接⼝。

顺序表分类:

2.2.1   静态顺序表

        概念:使⽤定⻓数组存储元素

我们来一点一点解释,在这串代码中我们使用了自定义的 typedef 我们把 int 重命名为 SLDateType

目的:是为了区分其他代码中的int ,  还有一个原因我们可以随时改变类型,在这个局部变量内部我们可以改变类型,假设我们想把int 类型改为char类型,我们直接修改即可。它不会影响程序内部其他的char,与int。

宏的作用:我们使用define来给N赋值,目的也很简单方便修改数组的大小。

静态顺序表缺陷:空间给少了不够⽤,给多了造成空间浪费 ------我们给的空间都是定义好的,没有空间去修改,给多少就是多少,不方便我们实际的使用。

   静态顺序表由于不实用我们在这里就着重讲一下动态顺序表。

好戏就要开始喽

2.2.2动态顺序表

我们来一步一步开始,首先我们创建好三个文件(一个头文件,两个源文件)。

这些文件有什么作用呢?

头文件:用来实现文件的声明与定义(定义顺序表要实现的结构\接口\方法等)

源文件:SeqList.c        具体实现接口和方法,实现程序的运行过程。

               text.c              实现测试作用,测试顺序表是否可以正常运行。

我们先从头文件开始

先实现静态顺序表

过程很简单和上面的一样

再来实现动态顺序表

我们接下来实现一下动态顺序表的 增加 删除 修改的功能。

初始化过程:着重详细讲解作为一个列子。

 我们在头文件中定义源文件中实现。

我们把空间都初始化为0;

初始化完成之后我们来进行测试(在text.c)文件中进行

我们创建了一个测试函数   slText01 用来实现。

当我们运行来试试是否初始化完成 ?

这是出了什么问题呢?

我们回头看看到底是哪出了问题

在传值的过程中我们会创建一个临时变量图中得到红色小方块,先把值放入这个临时创建的空间中然后完成调用

那么为什么会出现问题呢?

因为我们没有对sl 进行初始化(意味着sl是个无效值),我们没办法把值给拷贝下来放入临时创建的空间中传给s。

在这里我们就没办法进行传值操作了,只能进行传地址操作。

所以我们可以这样修改一下:

我们传地址然后使用指针来接收。

由于是指针类型我们不能继续使用点(.)来调用,而是使用指针类型的  ->  。

 当我们程序跑起来观察

程序没有问题,我们通过监视来看是否初始化成功

初始化之前:

初始化之后:

都变成了0,证明我们初始化成功。

我们对空间进行开辟(动态开辟)。数据的插入

头插             void SLPushFront(SL* ps, SLDataType x);

尾插              void SLPushBack(SL* ps, SLDataType x);

画图来进行分析:

 我们一个一个来讲解:

尾差

尾插有三种情况还是画图来展示:

大家肯定会有一个疑问,size不是有效数据的大小吗?在这里为什么是即将插入的下标呢?

其实size是有效元素的个数,但是也可以作为下一个即将插入元素的下标。

size就是下一个即将插入元素的下标,插入元素的时候直接用size作为下标,访问进行赋值
获取有效元素个数的时候,直接使用size。

扩容的原则:

关于动态内存管理我之前发布过专题博客很详细,感兴趣的可以看看,链接放下面了。

CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/136505981

关于为什么扩容大多数都是扩容二倍这个问题,现在的我能力有限还无法为大家解释清楚,但是请大家相信我,有朝一日我肯定会弄明白。

那我们接着继续:

空间足够时:

直接插入:关于为什么是size,上面有解释这里就不过多说了

                          size++是怎么回事呢? 是因为当我们插入一个数据的时候,size(这里指的是有效数据)就会增加1,所以我们需要++。

空间不够时:

我们可以看到size现在指向的是6的位置,我们在它的后面进行扩容。

我们来观察一下这个代码有没有问题。

仔细观察是有问题的,因为我们在初始化capacity是给的是0,在这里二倍*0还是0.

无法达到扩容的效果。

我修改了一下,大家看一下是否还是后问题:

答案是还是有问题,因为在这里我们使用三目操作符给的值是4个比特位,但是我在前面定义的是int类型。我们可以这样修改一下。

我们申请之后还需要判断是否申请成功,我们先创建一个临时变量来存放,如果申请成功了,我们就赋给newCapacity,如果没有申请成功就返回失败。

这就是尾插的全过程,这里讲的比较详细比较照顾刚入门的同学。

好了代码已经写完了我们现在来测试一下:

 现在为大家展示测试结果:

以上就是尾插的全过程。

有了尾插作为基础后面的就很好理解了

我们接下来头插

头插

这里有个100,我们现在要把它通过头插的方式插入到第0的位置。该怎么操作呢?

我们把数据往后挪动,使100可以插入。那么数据的挪动是从前往后,还是从后往前呢?

我们假设一下:从前往后,0挪到1,那么此时1被覆盖很有可能导致数据丢失。

                      :从后往前,3挪到空位置,然后2挪到原先3的位置,不会使数据丢失。

所以我们使用从后往前进行挪动。

原理很简单,我们来展示代码。

 我们来测试一下:

有了这些知识,剩下的就好理解了。

下面把全部代码展示给大家

#define INIT_CAPACITY 4
typedef int SLDataType;
// 动态顺序表 -- 按需申请
typedef struct SeqList
{
SLDataType* a;
int size; // 有效数据个数
int capacity; // 空间容量
}SL;
//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//头部插⼊删除 / 尾部插⼊删除
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//指定位置之前插⼊/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

后续会接着为大家讲解数据结构相关知识

请大家持续关注

感谢你的观看。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c语言中函数声明注意点都在这里了

C语言中函数声明主要分为三个大点:函数返回值类型、函数名和参数列表。 一、函数返回值类型 1. 无返回值的函数声明 无返回值的函数声明使用关键字void表示,表示该函数不返回任何值。例如: void print_hello(); // 声明一个无返回值的函数…

【Emgu CV教程】10.5、轮廓之凸包

文章目录 一、什么叫轮廓的凸包二、凸包函数三、二维点集寻找凸包四、绘制物体轮廓的凸包1.原始素材2.代码3.运行结果 一、什么叫轮廓的凸包 凸包是一个更加简化的多边形,是轮廓最外层的“凸”多边形,与前一篇多边形近似拟合不同的是,凸包组…

学生宿舍智能控电柜安装调试技术

学生宿舍智能控电柜安装调试石家庄光大远通电器有限公司宿舍控电限电管理系统是一种用于管理学生宿舍用电的智能系统,主要功能包括: 1.实时监控和控制:该系统能够实时监测和记录宿舍的用电情况,包括电器使用情况、电量消耗等。管理人员可以通过电脑或手机…

数据结构(五)——树与二叉树的应用

5.5 树与二叉树的应用 5.5.1 哈夫曼树 结点的权:有某种现实含义的数值。 结点的带权路径长度:从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积。 树的带权路径长度:树中所有叶结点的带权路径长度之和…

FPGA电平标准

1.LVTTL:(3.3v) 2.LVCOMS:(1.8v) 3.LVDS(1.8v):LVDS_25(2.5v) 4:如果是ddr3与fpga相连接fpga的vcco推荐(1.5v)…

【Linux】进程的基本概念(进程控制块,ps命令,top命令查看进程)

目录 01.进程的基本概念 程序与进程 进程的属性 02.进程控制块(PCB) task_struct的内容分类 组织进程 03.查看进程 ps命令 top指令 在计算机科学领域,进程是一项关键概念,它是程序执行的一个实例,是操作系统的…

【Linux C | 多线程编程】线程的退出

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 ⏰发布时间⏰: 本文未经允许…

第九届蓝桥杯大赛个人赛省赛(软件类)真题C 语言 A 组-乘积尾零

solution 找末尾0的个数&#xff0c;即找有多少对2和5 >问题等价于寻找所给数据中&#xff0c;有多少个2和5的因子&#xff0c;较少出现的因子次数即为0的个数 #include <iostream> using namespace std; int main() {// 请在此输入您的代码printf("31");…

项目3-留言板

1.创建项目 记得将project type改为maven 将需要的包引入其中 更改版本号 引入MYSQL相关包记得进行配置&#xff01;&#xff01;&#xff01; spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncodingutf8&useSSLfalseusername: rootpassword:…

MySQL将id相同的两行数据合并group_concat

MySQL将id相同的两行数据合并 group_concat这个函数能将相同的行组合起来&#xff0c;省老事了。 MySQL中group_concat函数 完整的语法如下&#xff1a; group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator ‘分隔符’]) 1.基本查询 Sql代码 2.…

力扣热门算法题 89. 格雷编码,92. 反转链表 II,93. 复原 IP 地址

89. 格雷编码&#xff0c;92. 反转链表 II&#xff0c;93. 复原 IP 地址&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.24 可通过leetcode所有测试用例。 目录 89. 格雷编码 解题思路 完整代码 Python Java 92. 反转链表…

SOC 子模块---中断控制器

中断控制器对soc 中的各个外设进行中断管理&#xff0c;进行优先权排队&#xff0c;并送出IQR信号给CPU&#xff1b; 中断控制器在整个系统中的结构&#xff1a; IRQ<n>来源于不同的中断源&#xff0c;比如&#xff1a;I2C,SPI等&#xff0c;INTC收集这些中断&#xff0…

从人工智能入门到理解ChatGPT的原理与架构的第一天(First)

目录 一.ChatGPT的发展历程 二.Attention is all you need 三.对于GPT-4的智能水平评估 四.大语言模型的技术演化 1.从符号主义到连接主义 2.特征工程 2.1数据探索 2.2数据清洗 2.3数据预处理 2.3.1无量纲化 2.3.1.1标准化 2.3.1.2区间缩放法 2.3.1.3标准化与归一…

Numpy使用中的十大经典routines函数

1.np.ones(shape, dtypeNone, order‘C’) np.ones(shape(3, 4, 3), dtypenp.int32)array([[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]],[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]],[[1, 1, 1],[1, 1, 1],[1, 1, 1],[1, 1, 1]]])2.np.zeros(shape, dtypefloat, order‘C’) …

P1835 素数密度题解

题目 给定区间[L,R]&#xff08;1≤L≤R<&#xff0c;R−L≤&#xff09;&#xff0c;请计算区间中素数的个数。 输入输出格式 输入格式 第一行&#xff0c;两个正整数L和R。 输出格式 一行&#xff0c;一个整数&#xff0c;表示区间中素数的个数。 输入输出样例 输…

Python库xarray:强大的多维数据处理工具

Python库xarray&#xff1a;强大的多维数据处理工具 在数据科学和科学计算领域&#xff0c;处理多维数据是一项常见而重要的任务。Python库xarray是一个功能强大的工具&#xff0c;专门用于处理、分析和可视化多维数据集。本文将深入介绍xarray库的特性、用法和优势&#xff0c…

网盘——客户端登陆注册注销请求

关于网盘设计&#xff0c;在客户端登录注册注销部分&#xff0c;主要有以下五个部分&#xff1a;消息类型、界面设计、注册、登录、注销 消息类型&#xff1a;我们可以把它写成枚举类型的 界面设计&#xff1a; 注册&#xff1a;用户名唯一&#xff0c;防止重复注册。查询数…

UI自动化_id 元素定位

## 导包selenium from selenium import webdriver import time1、创建浏览器驱动对象 driver webdriver.Chrome() 2、打开测试网站 driver.get("你公司的平台地址") 3、使浏览器窗口最大化 driver.maximize_window() 4、在用户名输入框中输入admin driver.find_ele…

编译u-boot(硬件: atk-dl6y2c)和NFS/EMMC模式启动Linux Kernel

目录 概述 1 编译u-boot 1.1 解压文件 1.2 编译u-boot 2 配置环境 2.1 在Ubunt 搭建TFTP 2.2 建立下载目录 3 烧写bootloader到SD 4 使用NFS模式启动板卡 5 从EMMC 启动 Linux 系统 5.1 通过配置参数方式 5.2 使用命令直接启动内核 文中使用的代码下载地址&#xf…

QT(3/25)

完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示“登录成功”&#xff0c;提供一个OK按钮&#xff0c;用户点击OK后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面。 如果账号和密码不匹配&#…