前端算法与数据结构——数组/栈/队列

数组

作为最简单,最基础的一个数据结构,大多数语言都天然地对数组有着原生的表达,Javascript亦然。

“开箱即用”,而不必自行实现,非常方便。

首先我们需要知道: JS 数组未必是真正的数组

在大多数的计算机语言中,数组都对应着一段连续的内存。如果我们想要在任意位置删除一个元素,那么该位置往后的所有元素,都需要往前挪一个位置;相应地,如果要在任意位置新增一个元素,那么该位置往后的所有元素也都要往后挪一个位置。

我们假设数组的长度是 n,那么因增加/删除操作导致需要移动的元素数量,就会随着数组长度 n 的增大而增大,呈一个线性关系。所以说数组增加/删除操作对应的复杂度就是 O(n)

但 JS 中不一定是。

JS比较特别。如果我们在一个数组中只定义了一种类型的元素,比如:

const arr = [1,2,3,4]

它是一个纯数字数组,那么对应的确实是连续内存。

但如果我们定义了不同类型的元素:

const arr = ['haha', 1, {a:1}]

它对应的就是一段非连续的内存。此时,JS 数组不再具有数组的特征,其底层使用哈希映射分配内存空间,是由对象链表来实现的。

所以说“JS 数组未必是真正的数组”。

在各大教材(包括百科词条)对数组的定义中,都有一个“存储在连续的内存空间里”这样的必要条件。

这同时是前端面试题中,数组和链表辨析的答案,我们要意识到 JS 数组和常规数组的不同,相对于数组来说,链表有个明显的有点,就是添加和删除元素都不需要挪动多余的元素。

Tips:要对数组格外走心,毕竟后面需要它帮忙的地方会非常多

数组的创建:

最多的创建方式:

const arr = [ 1, 2, 3 ]

但是在算法题中,很多时候我们初始化一个数组时,并不知道它内部元素的情况,这种场景下,推荐大家使用new的方式初始化数组

const arr = new Array()

// 等价于

const arr = []

不过我们使用构造函数,可不是为了创建空数组这么无聊。

我们需要它的时候,往往是因为我们有创造指定长度的空数组这样的需求。需要多长的数组就给它传多大的参数。

const arr = new Array(7)

// 创建一个指定长度为7的数组

在一些场景还需要我们创建一个指定长度,同时每一个元素的值也都确定的数组这时我们可以调用fill方法,假设需求是每一个坑里都填上一个1,只需给它fill一个1:

const arr = (new Array(7)).fill(1)

// [1,1,1,1,1,1,1]

数组的访问和遍历:

访问数组中的元素,我们直接在中括号中指定其索引即可:

arr[0]    // 访问索引下标为0的元素

而遍历数组,这个方法就多了,不过目的往往都是一致的(访问数组中的每一个元素,并且知道当前元素的索引)。这里我们介绍三个方法:

1.for循环

这是最基础的操作。我们可以通过循环数组的下标,来依次访问每个值:

// 获取数组的长度

const len = arr.length

for(let i=0;i<len;i++) {

    // 输出数组的元素值,输出当前索引 console.log(arr[i], i)

}

2.forEach方法

通过区forEach方法中传入函数的第一个入参和第二个入参,我们也可以取到数组每个元素的值及其对应索引:

arr.forEach((item, index)=> {

    // 输出数组的元素值,输出当前索引

    console.log(item, index)

})

3.map方法

map方法在调用形式上与forEach无异,区别于map方法会根据你传入的函数逻辑对数组的每一个元素进行处理,进而返回一个全新的数组。

所以其实map做的事情不仅仅是遍历,而是在遍历的基础上再加工。当我们需要对数组内容做批量修改,同时修改逻辑又高度一致时,就可以调用map来达到我们的目的:

const newArr = arr.map((item, index)=> {

    // 输出数组的元素值,输出当前索引

    console.log(item, index)

    // 在当前元素值的基础上加1

    return item+1

})

小建议:没有特殊的需求,统一使用for循环来实现遍历。因为从性能上看,for循环遍历起来是最快的

二维数组


一维数组


二维数组

二维数组的特点:从形状上看,相对于一维数组一条“线”一般的布局,二维数组更像是一个“面”。拿咱们这个例子来说,这里的二维数组逻辑分布图就宛如一个正方形。当然啦,如果我们稍微延长一下其中的一边,它也可以是一个矩形。

在数学中,形如这样长方阵列排列的复数或实数集合,被称为“矩阵”。因此二维数组的别名就叫“矩阵”

必须要记住“矩阵”和“二维数组”之间的等价关系。在算法题目中,见到“矩阵”时,能够立刻反射出它说的是二维数组,不被别名整懵逼,这就够了。

二维数组的初始化:

const arr =(new Array(7)).fill([])

以上的方式对吗?乍一看,没什么毛病。

但是当你想修改某一个坑里的数组的值的时候,你就会发现问题。

正确的初始化一个二维数组的方式:

const len = arr.length

for(let i=0;i<len;i++) {

    // 将数组的每一个坑位初始化为数组 arr[i] = []

}

二维数组的访问:

访问二维数组和访问一维数组差别不大,区别在于我们现在需要的是两层循环。

一维数组用 for 循环遍历只需一层循环,二维数组是两层,三维数组就是三层。依次类推,N 维数组需要 N 层循环来完成遍历

这远不是数组的全部,目前仅围绕数组最基本的操作进行介绍,在javascript数据结构中,数组几乎是基石一般的存在。


栈和队列

在javascript中,队列的实现一般都要依赖于数组,“特别的数组”。

(注:实际上,栈和队列作为两种运算受限的线性表,用链表来实现也是没问题的。只是从前端面试做题的角度来说,基于链表来实现栈和队列约等于脱裤子放屁(链表实现起来会比数组麻烦得多,做不到开箱即用),基本没人会这么干。这里大家按照数组的思路往下走就行了)

作为有经验的前端,大家对javascript数组的操作恐怕都不陌生。

但我们今天讲的栈和队列,两者的区别在于,它们各自对数组的增删操作有着不一样的限制。因此我们先熟悉一下javascript数组中的增删操作具有什么样的特性,对应的方法有哪些?

增加:

unshift 方法-添加元素到数组的头部

push 方法-添加元素到数组的尾部

splice 方法-添加元素到数组的任何位置

删除:

shift 方法-删除数组头部的元素

pop 方法-删除数组尾部的元素

splice 方法-删除数组任意位置的元素

栈(Stack)——只用 pop 和 push 完成增删的“数组”

栈是一种后进先出(LIFO,Last In First Out)的数据结构。

队列(Queue)——只用 push 和 shift 完成增删的“数组”

队列是一种先进先出(FIFO,First In First Out)的数据结构。

阅读掘金小册的《前端算法与数据结构面试:底层逻辑解读与大厂真题训练》所获。富有的朋友们值得购买一读。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容