88
99数据结构我们可以从逻辑上分为线性结构和非线性结构。线性结构有数组,栈,链表等, 非线性结构有树,图等。
1010
11- > 其实我们可以称树为一种半线性结构。
12-
13- 需要注意的是,线性和非线性不代表存储结构是线性的还是非线性的,这两者没有任何关系,它只是一种逻辑上的划分。
14- 比如我们可以用数组去存储二叉树。
15-
16- 一般而言,有前驱和后继的就是线性数据结构。比如数组和链表。
17-
18- > 其实一叉树就是链表。
11+ 需要注意的是,线性和非线性不代表存储结构是线性的还是非线性的,这两者没有任何关系,它只是一种逻辑上的划分。比如我们可以用数组去存储二叉树。一般而言,有前驱和后继的就是线性数据结构。比如数组和链表。
1912
2013### 数组
2114
22- 数组是最简单的数据结构了,很多地方都用到它。 比如有一个数据列表等,用它是再合适不过了。
23- 其实后面的数据结构很多都有数组的影子。
15+ 其实后面的数据结构很多都有数组的影子。数组是最简单的数据结构了,很多地方都用到它。 比如用一个数据列表存储一些用户的 id,就可以用数组进行存储。
2416
2517我们之后要讲的栈和队列其实都可以看成是一种` 受限 ` 的数组,怎么个受限法呢?我们后面讨论。
2618
27- 我们来讲几个有趣的例子来加深大家对数组这种数据结构的理解 。
19+ 接下来通过几个有趣的例子来加深大家对数组这种数据结构的理解 。
2820
29- #### React Hooks
21+ #### React Hooks(非前端党慎入)
3022
3123Hooks 的本质就是一个数组, 伪代码:
3224
@@ -77,7 +69,7 @@ function Form() {
7769
7870### 队列
7971
80- 队列是一种受限的序列,它只能够操作队尾和队首, 并且只能只能在队尾添加元素,在队首删除元素。
72+ 队列是一种 ** 受限 ** 的序列。受限在哪呢?受限就受限在它只能够操作队尾和队首, 并且只能只能在队尾添加元素,在队首删除元素。而数组就没有这个限制 。
8173
8274队列作为一种最常见的数据结构同样有着非常广泛的应用, 比如消息队列
8375
@@ -96,8 +88,9 @@ function Form() {
9688
9789(图片来自 https://github.com/trekhleb/javascript-algorithms/blob/master/src/data-structures/queue/README.zh-CN.md )
9890
99- 我们前端在做性能优化的时候,很多时候会提到的一点就是“HTTP 1.1 的队头阻塞问题”,具体来说
100- 就是 HTTP2 解决了 HTTP1.1 中的队头阻塞问题,但是为什么 HTTP1.1 有队头阻塞问题,HTTP2 究竟怎么解决的这个问题,很多人都不清楚。
91+ #### 队列的实际使用
92+
93+ 我们在做性能优化的时候,很多时候会提到的一点就是“HTTP 1.1 的队头阻塞问题”,具体来说就是 HTTP2 解决了 HTTP1.1 中的队头阻塞问题,但是为什么 HTTP1.1 有队头阻塞问题,HTTP2 究竟怎么解决的这个问题,很多人都不清楚。
10194
10295其实` 队头阻塞 ` 是一个专有名词,不仅仅在 HTTP 有,交换器等其他地方也都涉及到了这个问题。实际上引起这个问题的根本原因是使用了` 队列 ` 这种数据结构。
10396
@@ -133,7 +126,7 @@ function Form() {
133126
134127### 栈
135128
136- 栈也是一种受限的序列,它只能够操作栈顶 ,不管入栈还是出栈,都是在栈顶操作。
129+ 栈也是一种 ** 受限 ** 的序列,它受限就受限在只能够操作栈顶 ,不管入栈还是出栈,都是在栈顶操作。同样地,数组就没有这个限制 。
137130
138131在计算机科学中,一个栈 (stack) 是一种抽象数据类型,用作表示元素的集合,具有两种主要操作:
139132
@@ -152,6 +145,8 @@ function Form() {
152145
153146(图片来自 https://github.com/trekhleb/javascript-algorithms/blob/master/src/data-structures/stack/README.zh-CN.md )
154147
148+ #### 栈的应用(非前端慎入)
149+
155150栈在很多地方都有着应用,比如大家熟悉的浏览器就有很多栈,其实浏览器的执行栈就是一个基本的栈结构,从数据结构上说,它就是一个栈。
156151这也就解释了,我们用递归的解法和用循环+栈的解法本质上是差不多的。
157152
@@ -191,7 +186,7 @@ foo();
191186
192187(图片来自: https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/linked-list/traversal )
193188
194- #### React Fiber
189+ #### React Fiber(非前端慎入)
195190
196191很多人都说 fiber 是基于链表实现的,但是为什么要基于链表呢,可能很多人并没有答案,那么我觉得可以把这两个点(fiber 和链表)放到一起来讲下。
197192
@@ -250,7 +245,7 @@ return, children, sibling 也都是一个 fiber,因此 fiber 看起来就是
250245
251246## 非线性结构
252247
253- 那么有了线性结构,我们为什么还需要非线性结构呢? 答案是为了高效地兼顾静态操作和动态操作。大家可以对照各种数据结构的各种操作的复杂度来直观感受一下。
248+ 那么有了线性结构,我们为什么还需要非线性结构呢? 答案是为了高效地兼顾静态操作和动态操作, ** 我们一般使用树去管理需要大量动态操作的数据 ** 。大家可以对照各种数据结构的各种操作的复杂度来直观感受一下。
254249
255250### 树
256251
@@ -311,10 +306,11 @@ return, children, sibling 也都是一个 fiber,因此 fiber 看起来就是
311306
312307#### 堆
313308
314- 堆其实是一种优先级队列,在很多语言都有对应的内置数据结构,很遗憾 javascript 没有这种原生的数据结构。
315- 不过这对我们理解和运用不会有影响。
309+ 堆其实是一种优先级队列,在很多语言都有对应的内置数据结构,很遗憾 javascript 没有这种原生的数据结构。不过这对我们理解和运用不会有影响。
310+
311+ 堆的一种典型的实现就是二叉堆。
316312
317- 堆的特点 :
313+ 二叉堆的特点 :
318314
319315- 在一个 最小堆 (min heap) 中,如果 P 是 C 的一个父级节点,那么 P 的 key(或 value) 应小于或等于 C 的对应值。
320316 正因为此,堆顶元素一定是最小的,我们会利用这个特点求最小值或者第 k 小的值。
@@ -398,10 +394,12 @@ return, children, sibling 也都是一个 fiber,因此 fiber 看起来就是
398394- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
399395- 每个节点的所有子节点包含的字符都不相同。
400396
401- #### immutable 与 字典树
397+ #### immutable 与 字典树(非前端慎入)
402398
403399` immutableJS ` 的底层就是` share + tree ` . 这样看的话,其实和字典树是一致的。
404400
401+ 关于这点,我写过一篇文章 [ immutablejs 是如何优化我们的代码的?] ( https://mp.weixin.qq.com/s?__biz=MzA3MjU5NjU2NA==&mid=2455504106&idx=1&sn=8911bafed52aad42170b96f97b055b5c&chksm=88b349d1bfc4c0c7ab575711bbf5b3ca98423b60aed42ee9d9bfe43981336284e1440dd59f2e&token=967898660&lang=zh_CN#rd ) ,强烈建议前端开发阅读。
402+
405403相关算法:
406404
407405- [ 208.implement-trie-prefix-tree] ( ../problems/208.implement-trie-prefix-tree.md )
0 commit comments