数据结构与算法 - 顺序表与链表的区别

news2024/11/25 15:31:42

文章目录

前言

一、顺序表与链表的定义

1、顺序表

2、链表

二、区别

1、顺序表(动态顺序表):

2、链表(带头双向循环链表):

3、将上述文字用图表形式展示:

4、CPU高速缓存命中率

总结


前言

路漫漫其修远兮,吾将上下而求索;


一、顺序表与链表的定义

1、顺序表

顺序表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素;即,在顺序表中其数据必须连续存放,数据之间的空间不能有空

2、链表

不仅需要存储数据元素的信息,还要存储它后继元素的存储地址;

存储数据元素信息的域称为数据域,把存储其直接后继位置的域称为指针域。指针域中的存储信息称为指针或链。数据域 加上 指针域便构成了结点。

二、区别

顺序表与链表各有优缺,很难说明二者谁更优;准确来说这两个结构之间是相辅相承的关系;

1、顺序表(动态顺序表):

  • 逻辑结构上是线性的,物理结构上也上一定是线性结构
  • 支持随机访问(利用下标)
  • 但是在任意位置上插入或者删除数据需要一个一个地挪动数据以保证顺序表结构的连续性,时间复杂度为O(N),效率不高;
  • 并且插入数据,会面临扩容的问题,扩容本身就存在消耗就地扩容消耗不大(开辟空间,返回该空间的地址),但倘若是异地扩容,便会找新空间,拷贝旧空间的数据到新空间中,释放旧空间中的数据,返回新空间的地址;并且扩容的空间不一定能使用完,存在空间浪费的可能性。
  • 缓存利用率
  • 顺序表更适合于用来存储数据并且频繁访问的地方;

2、链表(带头双向循环链表):

  • 逻辑上是线性的,但是物理结构上不一定是线性的(取决于动态内存的分配策略);
  • 不支持随机访问,倘若想要访问第i 个结点中的数据,只能利用循环进行访问,时间复杂度为O(N);
  • 并且在任意位置插入、删除数据时不会有太大的消耗,只需改变结点之间的链接关系即可;
  • 插入数据时其结点是一个一个空间开辟的,不存在空间的浪费和很大的消耗;
  • 缓存利用率
  • 链表更适合于要对数据进行频繁修改(任意位置插入、删除数据)的地方;

3、将上述文字用图表形式展示:

顺序表(动态顺序表)链表(带头双向循环链表)
存储的空间逻辑结构上为线性,物理结构上也为线性逻辑结构上为线性,物理结构上不一定为线性(取决于动态空间的分配策略)
随机访问支持随机访问,利用下标不支持随机访问,需要遍历
任意位置插入、删除数据存在一个一个地挪动数据地可能性,效率低下,时间复杂度为O(N)均只需修改结点之间的链接关系即可
数据的插入动态顺序表中,当空间不够时需要进行扩容处理(扩容具有空间、时间的消耗)按需申请空间
CPU高速缓存命中率
适合的应用场景适用于存储数据并且频繁访问的地方适用于对数据进行频繁修改(任意位置插入、删除数据)的地方

链表并不是优于顺序表,他们有着不同的适用场景;

  • 例如,如果使用链表来对数据进行排序,其效率肯定比顺序表低;
  • 排序在我们的日常生活中是非常常见的;例如在购物平台上,我们可以对商品按照销量、价格等进行排序以帮助我们进行筛选;当商品在页面进行排序的时候,其底层是应用了顺序表这样的结构进行排序(不会用链表,因为用链表来排序,效率低下);

包括在后面的文章中会讲述的TOP-K问题(从n个数中找出最大的前k个数)、堆排序问题(二叉树的排序)均会要求使用支持随机访问的数据结构,其实这两个个问题的底层用到的是数组

针对顺序表与链表的结构特点,我们需要按照实际情况来选择;当此问题需要排序、二分查找等类似需要随机访问的算法,那么最好使用顺序表;当此问题无需排序,即无需对存储的数据进行随机访问的时候,而会对数据进行插入、删除,那么最好使用链表(注:此处仅仅只是举一个例子,还是需要根据具体问题具体分析来决定使用哪种结构);

接下来我们来了解一下,CPU高速缓存命中率;

4、CPU高速缓存命中率

无论你写什么样的代码均会交给CPU来执行,当前CPU具有多核技术;

从大的方面来说,对于单个计算机上的存储,分为带电存储不带电存储

带电存储

  • 包括寄存器、高速缓存、主存(主存就是电脑的内存);带电存储即有电才能存储数据,其中这三个结构中,最重要的是主存;

不带电存储

  • 包括本地二级存储(本地磁盘)、远程二级存储(分布式文件系统、Web服务器); 当你电脑关机的时候,你想要保存的数据存放在文件中,因为文件是存储在文件系统上即存储在磁盘或者硬盘上;

注:

1、磁盘(or 硬盘)是一种存储技术,当然还有一种技术叫做SSD(SSD 比磁盘会更快一些)

2、远程二级存储(分布式文件系统、Web服务器) 即网盘;例如,当你要将数据存入百度网盘之中,此数据便会通过网络传输以进行存储;

存储器的结构如下图所示:

注:电脑一般会有三级缓存(L1 cache、L2 cache、L3 cache)以及寄存器,三级缓存器与寄存器环绕在CPU周围;

为什么三级缓存与寄存器环绕在CPU周围?

  • 因为CPU执行的速度非常快,那么数据在主存中的速度相较于CPU来说就很慢,三级缓存与寄存器环绕在CPU周围就能稍微弥补存储传输上的时间,当CPU计算内存中的数据的时候,首先会将这些数据放入寄存器或者高速缓存之中;

例如,当你想要计算a+b 的值时,变量a 与变量b 的数据是存储在主存上的;如果a 、b 所占用的内存比较小(可放入寄存器之中,寄存器一般只能存放 4byte 或者8byte 的数据)的时候,变量a、b 会被加载进寄存器之中,然后在寄存器之中完成对二者的计算,最后再将计算的结果放回内存之中;如果变量a、b 所占用的内存比较大,那么便会借助于高速缓存

CPU是如何遍历顺序表和链表的呢?

首先我们先思考一下顺序表与链表中的数据存放在何处?显然是在上,因为顺序表与链表中存放数据的空间是动态开辟所得到的;

单单从物理结构上来说顺序表与链表的区别在于顺序表底层存储数据的空间是连续的,但是链表中底层存储数据的空间不一定是连续的,即多块不连续的空间利用指针链接在一起;

当你写下遍历顺序表或者遍历链表等代码的时候,程序的代码会经历编译、链接生成机器可读的二进制指令,CPU会执行这些二进制指令。当指令要遍历顺序表或者链表的时,CPU并不会直接去访问内存中的数据,CPU计算时使用的数据来自于三级缓存(L1 cache、L2 cache、L3 cache)以及寄存器;

这个过程是如何实现的?

(假设顺序表或者链表中第一个存放的数据为1,并且假设此数据很大,寄存器存放不下),若要访问存放数据1这块内存空间的位置,CPU会先看这块空间的地址是否在缓存中,如果在缓存中那么CPU便会直接访问,不在的话就CPU会先将此空间中的数据加载到缓存中,然后CPU再访问;在实际当中,当你访问了内存中的当前位置的数据马上可能会访问此位置相邻的数据("就近原则"),故而当将要访问空间中的数据加载到缓存时,会将此位置连续的一片空间加载到缓存之中(所要加载的“一片空间”的大小取决于内存);

假设顺序表和链表的数据均只有5个,并且CPU加载的一片空间的大小为假设为20 byte;

那么便意味着,当你第一次访问顺序表中存放数据1 的空间的地址时

CPU会先看这块空间的地址是否在缓存中,不在的话就会先将此空间中的数据以以及此空间开始向后连续的20byte 的空间的数据加载到缓存中;当CPU执行代码逻辑访问顺序表中下一空间的地址(存放数据2的空间),CPU发现此块空间的地址就在缓存中,在的话,即命中……故而在顺序表中的CPU高速缓存命中率高;

注:CPU缓存命中,即CPU执行指令所要访问的空间的地址在缓存或者寄存器中,那么便为命中;反之为未命中;

对于链表来说

由于其结点在空间中并不是连续存放的 (其结点的地址是否在物理结构连续取决于动态内存开辟的策略,有可能结点之间的距离隔得很近,但是大概率隔得很远(大于CPU加载地连续一片空间的大小)),即使CPU会将所要访问空间及其周围一片的空间中的数据加载到缓存中,大概率是需要一个结点一个结点地去加载,故而链表的CPU高速缓存命中率低;并且,此处的链表有5个结点,将此5个结点中的数据均加载进缓存的话,实际加载了100byte 的数据,而只会使用20byte 的数据,剩下80byte 的数据不会被CPU访问且还占用了缓存的空间,造成了缓存的污染(缓存污染简单来说就是将不会使用到的数据加载到缓存中);

注:缓存的大小是有限的;当你要将数据加载进缓存时,而缓存的空间不够用时,便会将缓存中最近未被访问的数据换出缓存;


总结

顺序表与链表各有优缺,很难说明二者谁更优;准确来说这两个结构之间是相辅相承的关系;要根据实际的使用情况来判断是使用顺序表更好,还是使用链表更好;

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

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

相关文章

Nginx实战指南:基础知识、配置详解及最佳实践全攻略

背景 在Java系统实现过程中,我们不可避免地会借助大量开源功能组件。然而,这些组件往往功能丰富且体系庞大,官方文档常常详尽至数百页。而在实际项目中,我们可能仅需使用其中的一小部分功能,这就造成了一个挑战&#…

数组中两个字符串的最小距离(图+文字详解)

链接:数组中两个字符串的最小距离__牛客网 题目:给定一个字符串数组strs,再给定两个字符串str1和str2,返回在strs中str1和str2的最小距离,如果str1或str2为null,或不在strs中,返回-1。 思路: 给定两个下标…

Pycharm 随时调整字体大小(放大或缩小)

实现按住 ctrl 滑动鼠标滚轮实现代码窗口字体大小调整: File 一>Settings 一>Editor一>General里 的Mouse Control把Change font size with CtrlMouse Wheel打上对勾,点击OK即可 使用快捷键 放大字体: Windows/Linux: Ctrl macOS…

IP报文格式、IPv6概述

IPv4报文格式 IPv4报文首部长度至少为20字节(没有可选字段和填充的情况下),下面来逐一介绍首部各个字段的含义 Version版本:表示采用哪一种具体的IP协议,对于IPv4来说该字段就填充4以表示,如果是IPv6就填充6IHL首部长度&#xff…

Android内容观察者(案例:监听数据库+代码+效果图)

目录 1.内容观察者概念 1. 什么是 ContentObserver? 2. 主要方法 3. 使用场景 4. 工作原理 5. 注册和注销 6. 实现步骤 7. 注意事项 2.创建内容观察者 3.注册内容观察者 4.取消注册内容观察者 5.完整的activity代码 6.案例:检测数据库 1)创建一个Android…

HTML(五)列表详解

在HTML中&#xff0c;列表可以分为两种&#xff0c;一种为有序列表。另一种为无序列表 今天就来详细讲解一下这两种列表如何实现&#xff0c;效果如何 1.有序列表 有序列表的标准格式如下&#xff1a; <ol><li>列表项一</li><li>列表项二</li>…

Linux下CMake入门

CMake的基础知识 什么是 CMake CMake 是一个跨平台的构建工具&#xff0c;主要用于管理构建过程。CMake 不直接构建项目&#xff0c;而是生成特定平台上的构建系统&#xff08;如 Unix 下的 Makefile&#xff0c;Windows 下的 Visual Studio 工程&#xff09;&#xff0c;然后…

《OpenCV计算机视觉》—— 人脸检测

文章目录 一、人脸检测流程介绍二、用于人脸检测的关键方法1.加载分类器&#xff08;cv2.CascadeClassifier()&#xff09;2.检测图像中的人脸&#xff08;cv2.CascadeClassifier.detectMultiscale()&#xff09; 三、代码实现 一、人脸检测流程介绍 下面是一张含有多个人脸的…

电子电气架构---软件定义汽车,产业变革

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

影刀RPA实战:操作Mysql数据库

1.摘要 影刀RPA&#xff08;Robotic Process Automation&#xff09;是一种软件自动化工具&#xff0c;它可以模拟人类用户执行各种重复性任务&#xff0c;其中包括对数据库的操作。 我们可以使用软件自动化指令&#xff0c;通过获取数据库窗口对象来操作数据库&#xff0c;也…

JSP 的 response 和 session 内置对象

文章目录 前言一、response 内置对象 1.重定向网页2.处理 HTTP 文件头3.设置输出缓存二、session 内置对象 1.创建及获取客户会话2.会话中移动指定的绑定对象3.销毁 session 内置对象4.会话超时的管理5. session 对象的应用总结 前言 JSP 的 response 和 session 内置对像&…

linux tar 打包文件去掉文件所在路径

一、准备目录 /root/tmp/images /root/tmp/images2 执行命令打包目录/root/tmp/images 到 /root/tmp/images.tar.gz 再解压到/root/tmp/images2 cd /root/tmp/images && tar -cvzf images.tar.gz * && mv images.tar.gz /root/tmp/ tar -C /root/tmp/image…

ctf.bugku-baby lfi 2

题目来源&#xff1a;baby lfi 2 - Bugku CTF平台 访问页面 翻译解析&#xff1a;百度翻译-您的超级翻译伙伴&#xff08;文本、文档翻译&#xff09; (baidu.com) LFI Warmups- level 2 -本地文件包含&#xff08;Local File Inclusion&#xff0c;简称LFI&#xff09; Hello…

力扣面试150 交错字符串 二维DP

Problem: 97. 交错字符串 &#x1f468;‍&#x1f3eb; 参考题解 class Solution {public boolean isInterleave(String s1, String s2, String s3) {int m s1.length();int n s2.length();if(s3.length() ! m n) return false;boolean[][] dp new boolean[m1][n1];dp[0]…

ZYNQ使用XGPIO驱动外设模块(后半部分)

目录 注意重点&#xff1a; 一、SDK代码开发部分&#xff1a; 显示所需的字符编码&#xff1a; 1.用于显示8x16的字符函数&#xff1a; 2.绘制图片: 3.清楚给定两个坐标之间的显示&#xff1a; 4.显示16*32的阿拉伯数字字符&#xff1a; 5.显示16*32的整型数字&#xff…

Excel:vlookup函数实现查找

1.要查找宋江的英语&#xff0c;把鼠标放在对应单元格然后开始编辑 2.选中所选区域&#xff0c;点击F4锁定区域&#xff0c;不然下拉填充的时候会变VLOOKUP 在查找时有严格要求&#xff0c;查找值必须在所选区域的第一列&#xff0c;因此如果你的查找值不在第一列&#xff0c;可…

TGRS 2024 面向雾天遥感图像的定向目标检测算法

TGRS 2024 | 面向雾天遥感图像的定向目标检测算法 论文信息 摘要 目前&#xff0c;大量工作集中在航空目标检测上&#xff0c;并取得了良好的结果。尽管这些方法在传统数据集上取得了有希望的结果&#xff0c;但在恶劣天气条件下捕获的低质量图像中定位对象仍然具有挑战性。目…

RabbitMQ 入门(四)SpringAMQP五种消息类型

一、WorkQueue(工作消息队列) Work queues&#xff0c;也被称为&#xff08;Task queues&#xff09;&#xff0c;任务模型。简单来说就是让多个消费者绑定到一个队列&#xff0c;共同消费队列中的消息。 当消息处理比较耗时的时候&#xff0c;可能生产消息的速度会远远大于…

【亲测可行】ubuntu下载安装c++版opencv4.7.0和4.5.0 安装opencv4.5.0报错及解决方法

文章目录 &#x1f315;系统配置&#x1f315;打开终端&#xff0c;退出anacoda激活环境(如果有的话)&#x1f315;安装依赖&#x1f319;安装g, cmake, make, wget, unzip&#xff0c;若已安装&#xff0c;此步跳过&#x1f319;安装opencv依赖的库&#x1f319;安装可选依赖 …

关于md5强比较和弱比较绕过的实验

在ctf比赛题中我们的md5强弱比较的绕过题型很多&#xff0c;大部分都是结合了PHP来进行一个考核。这一篇文章我将讲解一下最基础的绕过知识。 MD5弱比较 比较的步骤 在进行弱比较时&#xff0c;PHP会按照以下步骤执行&#xff1a; 确定数据类型&#xff1a;检查参与比较的两…