程序猿修仙之路--数据结构之你是否真的懂数组?

640?wx_fmt=gif640?wx_fmt=jpeg


640?wx_fmt=png

数据结构

但凡IT江湖侠士,算法与数据结构为必修之课。早有前辈已经明确指出:程序=算法+数据结构  。要想在之后的江湖历练中通关,数据结构必不可少。数据结构与算法相辅相成,亦是阴阳互补之法。

640?wx_fmt=jpeg

开篇

    

    说道数组,几乎每个IT江湖人士都不陌生,甚至过半人还会很自信觉的它很简单。 的确,在菜菜所知道的编程语言中几乎都会有数组的影子。不过它不仅仅是一种基础的数据类型,更是一种基础的数据结构。如果你觉的对数组足够了解,那能不能回答一下:

数组的本质定义?

数组的内存结构?

数组有什么优势?

数组有什么劣势?

数组的应用场景?

数组为什么大部分都从0开始编号?

数组能否用其他容器来代替?

定义


所谓数组,是相同的元素序列。数组是在程序设计中,为了处理方便,把具有相同类型的若干元素按无序的形式组织起来的一种形式。

——百科

640?wx_fmt=png


    正如以上所述,数组在应用上属于数据的容器。不过我还是要补充两点:

1.     数组在数据结构范畴属于一种线性结构,也就是只有前置节点和后续节点的数据结构,除数组之外,像我们平时所用的队列,栈,链表等也都属于线性结构。


640?wx_fmt=jpeg

    有线性结构当然就有非线性结构,比如之后我们要介绍的二叉树,图 等等,这里不再展开~~~

640?wx_fmt=jpeg


2.    数组元素在内存分配上是连续的。这一点对于数组这种数据结构来说非常重要,甚至可以说是它最大的“杀手锏”。下边会有更详细的介绍。

优势和劣势


640?wx_fmt=jpeg优势


    我相信所有人在使用数组的时候都知道数组可以按照下标来访问,例如 array[1] 。作为一种最基础的数据结构是什么使数组具有这样的随机访问方式呢?天性聪慧的你可能已经想到了:内存连续+相同数据类型。

现在我们抽象一下数据在内存上分配的情景。

640?wx_fmt=jpeg

1.    说到数组按下标访问,不得不说一下大多数人的一个“误解”:数组适合查找元素。为什么说是误解呢,是因为这种说法不够准确,准确的说数组适合按下标来查找元素而且按照下标查找元素的时间复杂度是O(1)。为什么呢?我们知道要访问数组的元素需要知道元素在内存中对应的内存地址,而数组指向的内存的地址为首元素的地址,即:array[0]。由于数组的每个元素都是相同的类型,每个类型占用的字节数系统是知道的,所以要想访问一个数组的元素,按照下标查找可以抽象为:

array[n]=array[0]+size*n

    以上是元素地址的运算,其中size为每个元素的大小,如果为int类型数据,那size就为4个字节。其实确切的说,n的本质是一个离首元素的偏移量,所以array[n]就是距离首元素n个偏移量的元素,因此计算array[n]的内存地址只需以上公式

640?wx_fmt=jpeg

    论证一下,如果下标从1开始计算,那array[n]的内存地址计算公式就会变为:

array[n]=array[0]+size*(n-1)

    对比很容易发现,从1开始编号比从0开始编号每次获取内存地址都多了一次 减法运算,也就多了一次cpu指令的运行。这也是数组从0下标开始访问一个原因。

    其实还有一种可能性,那就是所有现代编程语言的鼻祖:C语言,它是从0开始计数下标的,所以现在所有衍生出来的后代语言也就延续了这个传统。虽然不符合人类的思想,但是符合计算机的原理。当然也有一些语言可以设置为不从下标0开始计算,这里不再展开,有兴趣的可以去搜索一下。


2.     由于数组的连续性,所以在遍历数组的时候非常快,不仅得益于数组的连续性,另外也得益于cpu的缓存,因为cpu读取缓存只能读取连续内存的内容,所以数组的连续性正好符合cpu缓存的指令原理,要知道cpu缓存的速度要比内存的速度快上很多。


640?wx_fmt=jpeg劣势


1.    由于数组在内存排列上是连续的,而且要保持这种连续性,所以当增加一个元素或删除一个元素的时候,为了保证连续性,需要做大量元素的移动工作。

    举个栗子:要在数组头部插入一个新元素,为了在头部腾出位置,所有的元素都要后移一位,假设元素个数为n,这就导致了时间复杂度为O(n)的一次操作,当然如果是在数组末尾插入新元素,其他所有元素都不必移动,操作的时间复杂度为O(1)。

    当然这里有一个技巧:如果你的业务要求并不是数组连续有序的,当在位置k插入元素的时候,只需要把k元素转移到数组末尾,新元素插入到k位置即可。当然仔细沉思一下这种业务场景可能性太小了,数组都可以无序,我直接插入末尾即可,没有必要非得在k位置插入把。~~

    当然还有一个特殊场景:如果是多次连续的k位置插入操作,我们完全可以合并为一次“批量插入”操作:把k之后的元素整体移动sum(插入次数)个位置,无需一个个位置移动,把三次操作的时间复杂度合并为一次。

    与插入对应的就有删除操作,同理,删除操作数组为了保持连续性,也需要元素的移动。

    综上所述,数组在添加和删除元素的场景下劣势比较明显,所以在具体业务场景下应该避免频繁添加和删除的操作。


2.     数组的连续性就要求创建数组的时候,内存必须有相应大小的连续区块,如果不存在,数组就有可能出现创建失败的现象。在某些高级语言中(比如c#,golang,java)就有可能引发一次GC(垃圾回收)操作,GC操作在系统运行中是非常昂贵的,有的语言甚至会挂起所有线程的操作,对外的表现就是“暂停服务”。

3.    数组要求所有元素为同一个类型。在存储数据维度,它可能算是一种劣势,但是为了按照下标快速查找元素,业务中这也是一种优势。仁者见仁智者见智而已。

4.      数组是长度固定的数据结构,所以在原始数组的基础上扩容是不可能的,有的语言可能实现数组的“伪扩容”,为什么说是“伪”呢,因为原理其实是创建了一个容量更大的数组来存放原数组元素,发生了数据复制的过程,只不过对于调用者而已透明而已。

5.     数组有访问越界的可能。我们按照下标访问数组的时候如果下标超出了数组长度,在现代多数高级语言中,直接就会引发异常了,但是一些低级语言比如C 有可能会访问到数组元素以外的数据,因为要访问的内存地址确实存在。


640?wx_fmt=jpeg其他


    很多编程语言中你会发现“纯数组”并没有提供直接删除元素的方法(例如:c#,golang),而是需要将数组转化为另一种数据结构来实现数组元素的删除。比如在golang种可以转化为slice。这也验证了数组的不变性。


640?wx_fmt=jpeg


640?wx_fmt=gif


应用场景640?wx_fmt=gif

    我们学习的每个数据结构其实都有对应的适合场景,只不过是场景多少的问题,具体什么时候用,需要我们对该数据结构的特性做深入分析。

    关于数组的特性,通过以上介绍可以知道最大的一个亮点就是按照下标访问,那有没有具体业务映射这种特性呢?


1.      相信很多IT人士都遇到过会员机制,每个会员到达一定的经验值就会升级,怎么判断当前的经验是否到达升级条件呢?我们是不是可以这样做:比如当前会员等级为3,判断是否到达等级4的经验值,只需要array[4]的值判断即可,大多数人把配置放到DB,资源耗费太严重。也有的人放到其他容器缓存。但是大部分场景下查询的时间复杂度要比数组大很多。


2.     在分布式底层应用中,我们会有利用一致性哈希方案来解决每个请求交给哪个服务器去处理的场景。有兴趣的同学可以自己去研究一下。其中有一个环节:根据哈希值查找对应的服务器,这是典型的读多写少的应用,而且比较偏底层。如果用其他数据结构来解决大量的查找问题,可能会触碰到性能的瓶颈。而数据按下标访问时间复杂度为O(1)的特性,使得数组在类似这些应用中非常广泛。


640?wx_fmt=png


640?wx_fmt=gif

●程序猿修仙之路--算法之希尔排序!

●程序员修仙之路--算法之插入排序!

●程序员修仙之路--算法之选择排序!

640?wx_fmt=jpeg

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

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

相关文章

P5643-[PKUWC2018]随机游走【min-max容斥,dp】

正题 题目链接:https://www.luogu.com.cn/problem/P5643 题目大意 给出nnn个点的一棵树,一个人从点xxx开始随机游走,然后QQQ次询问给出一个点集SSS,求期望多少步这个人会经过这个点集中的所有点。 1≤n≤18,1≤Q≤50001\leq n\leq 18,1\leq…

Rolling The Polygon Gym - 102222B

Rolling The Polygon Gym - 102222B 题意: 给你一个多边形,给你内部一个点Q,多边形在平面上滚动一周(当有一个边第二次触地滚动停止),问Q的轨迹长度 题解: 计算几何题目 自己一直不是很擅长…

[杂题训练]CF1228E Another Filling the Grid(容斥),CF936C Lock Puzzle(构造)

文章目录T1:CF1228E Another Filling the GridsolutioncodeT2:CF936C Lock PuzzlesolutioncodeT1:CF1228E Another Filling the Grid 点我 solution 反过来思考,用所有方案数➖不合法方案数 很容易想到的是——容斥&#xff01…

Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章

前言事情的起因是由于一段简单的数据库连接代码引起,这段代码从语法上看,是没有任何问题;但是就是莫名其妙的报错了,这段代码极其简单,就是打开数据库连接,读取一条记录,然后立即更新到数据库中…

CF1146F: Leaf Partition(树形dp)

解析 阴间dp题qwq 不难设计dp: dpx,0:x节点没有被包含、子树内的方案数dp_{x,0}:x节点没有被包含、子树内的方案数dpx,0​:x节点没有被包含、子树内的方案数 dpx,1:x节点被包含、子树内的方案数dp_{x,1}:x节点被包含、子树内的方案数dpx,1​:x节点被包含、子树内的…

Take Your Seat Gym - 102222D

Take Your Seat Gym - 102222D 题意: 第一次是n个人坐飞机,按照1到n的顺序登机,第一个人登机牌丢了,他随机做一个座位,2到n个人上来按照自己的登机牌坐座位,如果他的座位被坐了,就在随机找一个…

CF446D-DZY Loves Games【高斯消元,矩阵乘法】

正题 题目链接:https://www.luogu.com.cn/problem/CF446D 题目大意 给出nnn个点mmm条边的一张无向图,一些点有陷阱,走到时会损失一条生命,总共有kkk条生命,求从111出发随机游走到nnn没有死亡且到终点时仅剩一条命的概率。 1≤n≤…

「BJOI2019」奥术神杖(AC自动机+DP)

文章目录titlesolutioncodetitle solution 令MagicViVjVk...MagicV_i\times V_j\times V_k...MagicVi​Vj​Vk​... 这里对Magicc\sqrt[c]{Magic}cMagic​有一个很巧妙的转换——取对数 Magicc(Magic)1celoge(Magic)1c\sqrt[c]{Magic}(Magic)^{\frac{1}{c}}e^{log_e(Magic)^{…

try.dot.net 的正确使用姿势

来源:https://www.cnblogs.com/7tiny/p/10277600.html【简介】微软官方前不久发布了 try.dot.net 这个有趣的网址,开始只是图个新鲜看了一下,后面通过自身实践过后,发现这着实算是个“有趣”的站点!首先我们大概地列举…

A - TOYS POJ - 2318

A - TOYS POJ - 2318 题意: 一个盒子中有n个隔板,分出n1个空间(从左往右空间的编号分别是0…n),(隔板之间不会相交,且按照从左往右的顺序给出),现在给你m个坐标的物品&…

CF1016F:Road Projects(树形dp)

解析 好题 意思就是我没做出来 稍微分析一下就可以发现加边的位置始终是一样的 换句话说询问完全可以O1 关键就是找到这条边加在哪里 一开始我完全把这道题看成了彻头彻尾的数据结构题 容易想到二分答案 然后上个树状树组搞一搞就行了 但是遇到一个关键的问题 它无法解决加边…

CF750E-New Year and Old Subsequence【动态dp】

正题 题目链接:https://www.luogu.com.cn/problem/CF750E 题目大意 给出一个长度为nnn的数字字符串,qqq次询问给出其的一个子串ttt,询问至少要删除多少个数字才能使得其中包含201720172017这个子序列却不包含201620162016这个子序列。 1≤n,q≤21051\l…

[BJOI2017]魔法咒语(AC自动机+DP+矩阵快速幂)

文章目录titlesolutioncodetitle solution 针对数据编程才是坠吊的!!! 观察数据,发现分隔数据的LLL跨度过大,没有衔接——推测很有可能是分数据做法 ①:考虑L≤100L\le100L≤100的情况 可以暴力DPDPDP转移…

P6242-[模板]线段树3【吉司机线段树】

正题 题目链接:https://www.luogu.com.cn/problem/P6242 题目大意 给出一个长度为nnn的序列aaa,mmm次要求支持操作 区间加上一个值kkk区间所有aia_iai​变为min{ai,k}min\{a_i,k\}min{ai​,k}区间求和区间求最大值区间求历史最大值 1≤n,q≤51051\leq n,q\leq 5\…

洛谷P1912:诗人小G(二分栈、决策单调性)

二分栈,就是通过二分维护的栈 (逃) 解析 本题的决策单调性可以说是显然 但是本题是同维度(其实只有一维)自左向右转移,分治的写法是不能奏效的 所以我们使用决策点调性的另一种实现方法:二分栈…

[国家集训队]middle(二分+主席树[中位数思维题])

文章目录点击查看solutioncode点击查看 solution 简单口胡一下就跑 考虑二分答案ansansans 区间[x1,x2],x1∈[a,b],x2∈[c,d][x1,x2],x1∈[a,b],x2∈[c,d][x1,x2],x1∈[a,b],x2∈[c,d] 大于等于ansansans的设为111,小于ansans…

使用Roslyn脚本化C#代码,C#动态脚本实现方案

来源:https://www.cnblogs.com/7tiny/p/10279349.html【前言】Roslyn 是微软公司开源的 .NET 编译器。编译器支持 C# 和 Visual Basic 代码编译,并提供丰富的代码分析 API。Roslyn不仅仅可以直接编译输出,难能可贵的就是上述描述中的开放了编…

Moving On Gym - 102222F

Moving On Gym - 102222F 题意: 有 n 个城市,q 次询问. 给出每个城市的危险度 r 和 城市的邻接矩阵. 每次询问给出 u、v、w,求从 u 到 v 且不经过其他危险度超过 w 的城市的最短路. 题解: floyd 变形 我队友一开始想的是每次…

10.27模拟 总结

前言 220pts 100200100 按照gg的建议从《暴力模式》转化为《切题模式》 但是感觉本次有点难阿… 进入石头门困境… 再四道题中反复横跳 说实话心态是炸的 T1(伪)正解出来后才安了一些心 由于这次数据的强度确实不高 T1和T4的做法其实都很假 过掉也有运气…

[构造训练]CF1227G Not Same,CF1375H Set Merging,CF1364E X-OR

文章目录T1:CF1227G Not SamesolutioncodeT2:CF1364E X-ORsolutioncodeT3:CF1375H Set Mergingsolutioncode~~脑子是个好东西,希望人人都有构造真的不是个东西,看了一天视频,没有一道题会做~~ T1&#xff…