数据结构2:顺序表和链表

news2024/12/25 18:43:46

目录

1.线性表

2.顺序表

2.1概念及结构

2.2接口实现

2.3数据相关面试题

2.4顺序表的问题及思考

3.链表

3.1链表的概念及结构

3.2链表的分类

3.3链表的实现

3.4链表面试题

3.5双向链表的实现

4.顺序表和链表的区别


1.线性表

线性表(linear list)是具有相同特征的数据元素的有限序列。线性表是一种在实际中广泛应用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就是说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式的形式存储。

2.顺序表

2.1概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素。
  2. 动态顺序表:使用动态开辟的数组存储。

2.2接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表。根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
    SLDataType* array; // 指向动态开辟的数组
    size_t size ; // 有效数据个数
    size_t capicity ; // 容量空间的大小
}SeqList;
// 基本增删查改接口

// 顺序表初始化
void SeqListInit(SeqList* psl, size_t capacity);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* psl);
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* psl);
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);

2.3数据相关面试题

  1. 原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度为O(1).答案
  2. 删除排序数组中的重复项。
  3. 合并两个有序数组。

2.4顺序表的问题及思考

问题:

  1. 中间/头部的插入删除,时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么久浪费了95个数据空间。

思考:如何解决上面的问题呢?

3.链表

3.1链表的概念及结构

概念:链表是一种物理存储架构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

 现实中数据结构中

注意:

  1. 链式结构在逻辑上是连续的,但是在物理上不一定连续
  2. 现实中的节点一般是从堆上申请出来的
  3. 从堆上申请的空间,是按照一定的策略来分配的,两次的申请的的空间可能连续,也可能不连续。 

假设在32位系统上,节点中值域为int类型,则一个节点的大小为8个字节,则也可能有下述链表:

  

3.2链表的分类

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

  1. 单项或者双向
  2. 带头或者不带头
  3. 循环或者非循环

虽然有这么多的链表的结构,但是我们实际中最常用的还是两种结构:

  1. 无头单项非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等,另外这种结构在笔试面试中出现很多。
  2. 带头双向循环链表:结构最复杂,一般用来单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。虽然结构复杂,但是使用代码实现以后会发现结构会带来更多优势实现反而简单了。

3.3链表的实现

 单链表的实现(无头+单向+非循环链表增删查改实现)

3.4链表面试题

  1. 删除链表中等于给定值 val 的所有节点。 答案
  2. 反转一个单链表。 答案
  3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。答案
  4. 输入一个链表,输出该链表中倒数第k个结点。答案
  5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。答案
  6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。答案
  7. 链表的回文结构。答案
  8. 输入两个链表,找出它们的第一个公共结点。答案
  9. 给定一个链表,判断链表中是否有环。 答案

    【思路】

    快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表的起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。

    【扩展问题】

    1. 为什么快指针每次走两步,慢指针走一步可以?

    假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

    2. 快指针一次走3步、走4步、走n步可以吗?

    假设:快指针每次走3步,慢指针每次走一步,快指针肯定先进环,慢指针后进环。假设慢指针进环的时候,快指针的位置如图所示:

    此时按照上述方法来绕环移动,每次快指针走3步,慢指针走1步,是永远不会相遇的,快指针刚好将慢指针套圈了,因此不行。

    只有快指针走2步,慢指针走1步才可以,因为换的最小长度是1,即使套圈了两个也在相同的位置。 

  10. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL 。答案

    结论:

    让一个指针从链表的起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。

  11. 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深度拷贝。答案

3.5双向链表的实现

双向链表的实现(带头+双向+循环链表增删查改实现)

4.顺序表和链表的区别

不同点顺序表链表
存储空间物理上一定连续逻辑上连续,但是物理上不一定连续
随机访问支持O(1)不支持O(N)
任意位置插入或删除元素可能需要搬移元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够时需要扩容。没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入或删除频繁
缓存利用率

缓存利用率:

当SRAM拜访DRAM时,会默认加载一段数据(假设32byte - 与硬件有关)而不是一个数据(假设4byte),

  • 加载顺序表,就会直接加载到有效数据(物理内存是连续的),接下来直接访问之后的有效数据。
  • 加载链表,加载到一个有效数据,其后面跟随的数据不一定是有效数据(链表的的存储在物理内存上是不连续的),此时就带来的缓存污染(将非有效数据读取进SRAM)。

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

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

相关文章

Qt QImage scaled方法缩放中的问题

最近在某些测试中发现,QImage 先按照一定的比例进行缩放,在对QImage对象进行绘制等操作后,使用以下的方式将其恢复到其原来的尺寸。 图像的缩放是这样的: void ImageBaseWidget::zoomImage(QMouseEvent *event) {if (event->…

传输层协议——TCP协议

传输层协议——TCP协议认识IP地址TCP/IP的分层管理TCP/IP分层通信示例(发送数据包)认识IP地址 IP地址属于网络层地址 在计算机通信中,为了识别通信对端,必须有一个类似于地址的识别码进行标识。IP地址用于在连接到网络中的所有主…

利用seaborn、statannotations库绘制显著性标注

如何使用Python-SeabornSeaborn进行显著性统计图表绘制,详细内容如下: Python-Seaborn自定义函数绘制Python-statannotations库添加显著性标注 1、Python-Seaborn 自定义函数绘制 import matplotlib.pylab as plt import numpy as np import seaborn as…

Spring Cloud组件源码之LoadBalancer源码分析

" Spring 到底是春天的来临万物复苏,还是春转夏的干燥又炎热呢?" Spring的来临让JavaEE走向了另一个高度。便捷的开发,完美的生态。物极必反,学习Spring的成本越来越低,导致Java程序员越来越密集&#xff0…

1、Windows下编译并搭建AzerothCore服务端

目录前言一、AzerothCore下载二、mysql安装三、boost安装四、OpenSSL安装五、CMake下载六、CMake编译1 - CMake生成vs项目2 - vs项目设置3 - 生成解决方案4 - 安装AzerothCore5 - 添加账号6 - 修改服务器名称7 - 修改客户端的服务器地址前言 客户端对应版本:魔兽世…

CANopen | 对象字典OD 07 - 创建对象字典变量,变量变化时发送TPDO1,滤波时间200ms

文章目录一、前言二、实验目的三、对象字典OD四、TPDO1数据变化发送,滤波时间200ms4.1、main.c4.2、让CANopen从站进入操作状态4.3、TPDO1的CAN数据包一、前言 该笔记的程序:github 二、实验目的 CANopen从站有一个变量tx_Value,映射到T…

我调用第三方接口遇到的13大坑

前言 在实际工作中,我们经常需要在项目中调用第三方API接口,获取数据,或者上报数据,进行数据交换和通信。 那么,调用第三方API接口会遇到哪些问题?如何解决这些问题呢? 这篇文章就跟大家一起…

ubuntu防火墙命令介绍

ubuntu在开启ufw防火墙前,为了避免与iptables现有规则冲突,建议先清空iptables的所有规则。相关命令如下: iptables -F 更改iptables规则链默认操作命令如下: iptables -P INPUT ACCEPTiptables -P FORWARD ACCEPTiptables -P …

【PyTorch】第一节:张量(Tensor)的定义

作者🕵️‍♂️:让机器理解语言か 专栏🎇:PyTorch 描述🎨:PyTorch 是一个基于 Torch 的 Python 开源机器学习库。 寄语💓:🐾没有白走的路,每一步都算数&#…

云原生网络之微隔离

本博客地址:https://security.blog.csdn.net/article/details/130044619 一、微隔离介绍 1.1、微隔离概念 在主体执行动作时,对主体权限和行为进行判断,最常见的是网络访问控制,也就是零信任网络访问(ZTNA&#xff…

TP5 解决如何实现生成并导出Word文档功能

今天连续更新两篇文章,上一篇讲了一下如何生成PDF并导出文件的功能 接下来我们就来拼一拼怎么实现生成并导出word文档的功能 话不多说 我们直接上流程: 1.下载安装phpword插件:composer require phpoffice/phpword 2.安装成功后该插件在我们项…

Linux——高级I/O操作(三)

目录 I/O多路复用 异步I/O I/O多路复用 阻塞型I/O 相对于非阻塞型 I/O 来说,最大的优点就是在设备的资源不可用时,进程主动放弃 CPU,让其他的进程运行,而不用不停地轮询,有助于提高整个系统的效率。但是其缺点也是比…

Sharding-JDBC之水平分表

目录一、简介1.1、垂直分表1.2、水平分表二、maven依赖三、数据库3.1、创建数据库3.2、创建表四、配置(二选一)4.1、properties配置4.2、yml配置五、实现5.1、实体5.2、持久层5.3、服务层5.4、测试类5.4.1、保存数据5.4.2、查询数据一、简介 1.1、垂直分…

Java入坑之注解和反射

一、注解概念0 1.1基本定义 Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能 1。它们可以用来标记类、方法、变量、参数和包等 简而言之,注解就是对于代码中某些鲜活个体的贴上去的一张…

企业如何开发自己的小程序

小程序是一种轻量级的应用程序,被广泛用于社交娱乐、电商购物等领域。对于企业而言,开发自己的小程序可以为客户提供更加个性化的服务,提高品牌认知度和用户忠诚度。本文将介绍企业如何开发自己的小程序,并通过一个具体的案例来说…

【CSS】图片底部空白缝隙处理 ( 使用居中对齐 / 顶部对齐 / 底部对齐 | 将行内元素 / 行内块元素转为块级元素 )

文章目录一、图片底部空白缝隙问题二、图片底部空白缝隙问题解决方案一 ( 使用居中对齐 / 顶部对齐 / 底部对齐 )三、图片底部空白缝隙问题解决方案二 ( 将行内元素 / 行内块元素转为块级元素 )一、图片底部空白缝隙问题 在上一篇博客中 , 使用默认的基线对齐 , 会发现 行内块级…

java 利用正则来分析日志(IT枫斗者)

利用正则来分析日志(IT枫斗者) 环境接口的历史并发数,然而运维并没有做相关的统计,没办法,只能拿到服务器近一个月的 Nginx access 日志,根据正则匹配所有我的接口服务的日志,然后统计每一秒内…

《低代码PaaS驱动集团企业数字化创新白皮书》-平台化加低代码提供破解之道(2)

平台化加低代码提供破解之道 低代码向业务的赋能:以效率和创新为核心,提升组织效率,促进创新,优化体验 通过IDC对大型企业的调研发现,当前拥有100个及以上应用数量的企业已经高达70%;IDC预测 ,2025年&…

〖Python网络爬虫实战⑮〗- pyquery的使用

订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000python项目实战 Python编程基础教程系列(零基础小白搬砖逆袭) 说明:本专栏持续更新中,目前专栏免费订阅,在转为付费专栏前订阅本专栏的,可以免费订阅付费…

数据结构——队列(C语言实现)

队列的概念与结构 队列是一种特殊的线性结构,数据只能在一端插入,数据也只能在另一端进行删除。插入数据的那一端称之为队尾,插入数据的动作称之为入队。删除数据的那一端称之为队头,删除数据的动作称之为出列。队列遵守的是FIFO…