React Algorithm
React Algorithm
位运算(bit-operation)
特性
位运算在计算机中作为非常底层的运算,速度快,但不太直观且不支持整数运算。
- 位运算只能在整型变量之间进行运算
- js 中的Number类型在底层都是以浮点数(参考 IEEE754 标准)进行存储
- js 中所有的按位操作符的操作数都会被转成补码形式的有符号32位整数
位运算 | 用法 | 描述 |
---|---|---|
按位与(& ) | a & b | 对于每一个比特位,两个操作数都为 1 时, 结果为 1, 否则为 0 |
按位或(| ) | a | b | 对于每一个比特位,两个操作数都为 0 时, 结果为 0, 否则为 1 |
按位异或(^ ) | a ^ b | 对于每一个比特位,两个操作数相同时, 结果为 0, 否则为 1 |
按位非(~ ) | ~ a | 反转操作数的比特位, 即 0 变成 1, 1 变成 0 |
左移(<< ) | a << b | 将 a 的二进制形式向左移 b (< 32) 比特位, 右边用 0 填充 |
有符号右移(>> ) | a >> b | 将 a 的二进制形式向右移 b (< 32) 比特位, 丢弃被移除的位, 左侧以最高位来填充 |
无符号右移(>>> ) | a >>> b | 将 a 的二进制形式向右移 b (< 32) 比特位, 丢弃被移除的位, 并用 0 在左侧填充 |
基础使用
- 定义一些枚举常量
1
2
3const A = 1 << 0; // 0b00000001
const B = 1 << 1; // 0b00000010
const C = 1 << 2; // 0b00000100 - 位掩码特性 快速操作实现增加、删除、比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const A = 1 << 0; // 0b00000001
const B = 1 << 1; // 0b00000010
const C = 1 << 2; // 0b00000100
// 增加属性
const ABC = A | B | C; // 0b00000111
// 删除属性
const AB = ABC & ~C; // 0b00000011
// 属性比较
// 1. AB当中包含B
console.log((AB & B) === B); // true
// 2. AB当中不包含C
console.log((AB & C) === 0); // true
// 3. A和B相等
console.log(A === B); // false
react中使用
优先级管理 lanes
1 | //类型定义 |
方法定义
1 | // 分离出最高优先级 得到此lanes中最右边的的1 |
执行上下文 ExecutionContext
1 | export const NoContext = /* */ 0b0000000; |
方法定义
1 | // scheduleUpdateOnFiber函数中包含了好多关于executionContext的判断(都是使用位运算) |
深度优先遍历(dfs)
概念
是一种用于遍历或搜索树或者图的算法。
1 | // 实现方式1 递归 |
react中使用
- 深度优先遍历在react中的经典应用场景是ReactElement与fiber树的构造过程
- 使用context时,深度优先查找消费的context节点
堆排序(heap-sort)
概念
最常见的堆结构就是二叉堆。二叉堆也是完全二叉树(注意和满二叉树区分),即对于节点为n,深度为k的二叉树与节点n,深度为k的满二叉树除了最后一层外一一对应。
堆排序利用二叉根的特性,对根节点循环提取,从而达到排序目的,时间复杂度o(nlogn)。
特性
- 父节点的值大于等于子节点的值(最大堆),父节点的值小于等于子节点的值(最小堆)
- 假设一个数组[k0, k1, k2, …kn]下标从 0 开始. 则ki <= k2i+1,ki <= k2i+2 或者 ki >= k2i+1,ki >= k2i+2 (i = 0,1,2,3 .. n/2)
排序使用
- 一次循环完 heapInsert构造大顶堆或小顶堆
1
2
3
4
5
6
7
8
9
10
11function heapInsert(arr, curIndex) {
while (arr[curIndex] > arr[((curIndex - 1) / 2) >>> 0]) {
swap(arr, curIndex, ((curIndex - 1) / 2) >>> 0)
curIndex = ((curIndex - 1) / 2) >>> 0
}
}
// 1. 构造大顶堆
for (let i = 0; i < arr.length; i++) {
heapInsert(arr, i)
} - 循环提取根节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// 向下调整的过程 始终保持一个大顶堆状态
function heapify(arr, index, size) {
let leftIndex = 2 * index + 1
while (leftIndex < size) {
// 左右子树最大的一位
let largestBtw =
leftIndex + 1 < size && arr[leftIndex + 1] > arr[leftIndex]
? leftIndex + 1
: leftIndex
let largest = arr[index] > arr[largestBtw] ? index : largestBtw
// 如果都大于子树 停止
if (largest === index) break
swap(arr, index, largest)
index = largest
leftIndex = 2 * index + 1
}
}
// 2. 循环提取根节点
// 2.1 将根节点与末尾元素交换 heapSize减1
// 2.2 交换之后进行向下调整
let heapSize = arr.length
while (heapSize--) {
swap(arr, 0, heapSize)
// 向下调整达到保持大顶堆
heapify(arr, 0, heapSize)
}
react中使用
对于二叉堆的应用在scheduler
,有两个数组taskQueue和timerQueue,它们都是以最小堆的形式存储。
栈(stack)
概念
栈是一个先入后出(FILO-FirstInLastOut)的有序列表。
特性
- 先入后出,后入先出
- 除头尾节点之外, 每个元素有一个前驱, 一个后继
基本使用
1 | class Stack { |
react中使用
- context状态管理 ReactFiberStack.js中定义
- executionContext 执行上下文
链表操作 (linked-list)
概念
链表是一种常见的基础数据,是一种线性表。
特性
- 物理上不连续,逻辑上连续
- 单向链表: 每个节点包含两个域, 一个信息域和一个指针域. 这个指针指向列表中的下一个节点, 而最后一个节点则指向一个空值
- 双向链表: 每个节点有两个连接, 一个指向前一个节点(第一个节点指向空值), 而另一个指向下一个节点(最后一个节点指向空值)
- 循环链表: 在单向链表的基础上, 首节点和末节点被连接在一起
基本使用
1 | // 定义Node节点类型 |
react中使用
- fiber对象
- hook对象
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 AresのBlog!