Add captions for all the animations.

pull/392/head
krahets 2 years ago
parent 7aa44d212c
commit 23cda5e225

@ -12,7 +12,7 @@
- **初始化**:传入 $n$ 个顶点,初始化长度为 $n$ 的顶点列表 `vertices` ,使用 $O(n)$ 时间;初始化 $n \times n$ 大小的邻接矩阵 `adjMat` ,使用 $O(n^2)$ 时间。 - **初始化**:传入 $n$ 个顶点,初始化长度为 $n$ 的顶点列表 `vertices` ,使用 $O(n)$ 时间;初始化 $n \times n$ 大小的邻接矩阵 `adjMat` ,使用 $O(n^2)$ 时间。
=== "初始化邻接矩阵" === "初始化邻接矩阵"
![adjacency_matrix_initialization](graph_operations.assets/adjacency_matrix_initialization.png) ![邻接矩阵的初始化、增删边、增删顶点](graph_operations.assets/adjacency_matrix_initialization.png)
=== "添加边" === "添加边"
![adjacency_matrix_add_edge](graph_operations.assets/adjacency_matrix_add_edge.png) ![adjacency_matrix_add_edge](graph_operations.assets/adjacency_matrix_add_edge.png)
@ -99,7 +99,7 @@
- **初始化**:需要在邻接表中建立 $n$ 个结点和 $2m$ 条边,使用 $O(n + m)$ 时间。 - **初始化**:需要在邻接表中建立 $n$ 个结点和 $2m$ 条边,使用 $O(n + m)$ 时间。
=== "初始化邻接表" === "初始化邻接表"
![adjacency_list_initialization](graph_operations.assets/adjacency_list_initialization.png) ![邻接表的初始化、增删边、增删顶点](graph_operations.assets/adjacency_list_initialization.png)
=== "添加边" === "添加边"
![adjacency_list_add_edge](graph_operations.assets/adjacency_list_add_edge.png) ![adjacency_list_add_edge](graph_operations.assets/adjacency_list_add_edge.png)

@ -87,7 +87,7 @@ BFS 常借助「队列」来实现。队列具有“先入先出”的性质,
代码相对抽象,建议对照以下动画图示来加深理解。 代码相对抽象,建议对照以下动画图示来加深理解。
=== "<1>" === "<1>"
![graph_bfs_step1](graph_traversal.assets/graph_bfs_step1.png) ![图的广度优先遍历步骤](graph_traversal.assets/graph_bfs_step1.png)
=== "<2>" === "<2>"
![graph_bfs_step2](graph_traversal.assets/graph_bfs_step2.png) ![graph_bfs_step2](graph_traversal.assets/graph_bfs_step2.png)
@ -227,7 +227,7 @@ BFS 常借助「队列」来实现。队列具有“先入先出”的性质,
为了加深理解,请你将图示与代码结合起来,在脑中(或者用笔画下来)模拟整个 DFS 过程,包括每个递归方法何时开启、何时返回。 为了加深理解,请你将图示与代码结合起来,在脑中(或者用笔画下来)模拟整个 DFS 过程,包括每个递归方法何时开启、何时返回。
=== "<1>" === "<1>"
![graph_dfs_step1](graph_traversal.assets/graph_dfs_step1.png) ![图的深度优先遍历步骤](graph_traversal.assets/graph_dfs_step1.png)
=== "<2>" === "<2>"
![graph_dfs_step2](graph_traversal.assets/graph_dfs_step2.png) ![graph_dfs_step2](graph_traversal.assets/graph_dfs_step2.png)

@ -487,7 +487,7 @@
考虑从入堆结点开始,**从底至顶执行堆化**。具体地,比较插入结点与其父结点的值,若插入结点更大则将它们交换;并循环以上操作,从底至顶地修复堆中的各个结点;直至越过根结点时结束,或当遇到无需交换的结点时提前结束。 考虑从入堆结点开始,**从底至顶执行堆化**。具体地,比较插入结点与其父结点的值,若插入结点更大则将它们交换;并循环以上操作,从底至顶地修复堆中的各个结点;直至越过根结点时结束,或当遇到无需交换的结点时提前结束。
=== "<1>" === "<1>"
![heap_push_step1](heap.assets/heap_push_step1.png) ![元素入堆步骤](heap.assets/heap_push_step1.png)
=== "<2>" === "<2>"
![heap_push_step2](heap.assets/heap_push_step2.png) ![heap_push_step2](heap.assets/heap_push_step2.png)
@ -597,7 +597,7 @@
顾名思义,**从顶至底堆化的操作方向与从底至顶堆化相反**,我们比较根结点的值与其两个子结点的值,将最大的子结点与根结点执行交换,并循环以上操作,直到越过叶结点时结束,或当遇到无需交换的结点时提前结束。 顾名思义,**从顶至底堆化的操作方向与从底至顶堆化相反**,我们比较根结点的值与其两个子结点的值,将最大的子结点与根结点执行交换,并循环以上操作,直到越过叶结点时结束,或当遇到无需交换的结点时提前结束。
=== "<1>" === "<1>"
![heap_poll_step1](heap.assets/heap_poll_step1.png) ![堆顶元素出堆步骤](heap.assets/heap_poll_step1.png)
=== "<2>" === "<2>"
![heap_poll_step2](heap.assets/heap_poll_step2.png) ![heap_poll_step2](heap.assets/heap_poll_step2.png)

@ -15,7 +15,7 @@
3. 循环执行步骤 1-2 ,直到找到拼音首字母为 $r$ 的页码时终止。 3. 循环执行步骤 1-2 ,直到找到拼音首字母为 $r$ 的页码时终止。
=== "<1>" === "<1>"
![look_up_dictionary_step_1](algorithms_are_everywhere.assets/look_up_dictionary_step_1.png) ![查字典步骤](algorithms_are_everywhere.assets/look_up_dictionary_step_1.png)
=== "<2>" === "<2>"
![look_up_dictionary_step_2](algorithms_are_everywhere.assets/look_up_dictionary_step_2.png) ![look_up_dictionary_step_2](algorithms_are_everywhere.assets/look_up_dictionary_step_2.png)

@ -25,7 +25,7 @@ $$
首先,我们先采用“双闭区间”的表示,在数组 `nums` 中查找目标元素 `target` 的对应索引。 首先,我们先采用“双闭区间”的表示,在数组 `nums` 中查找目标元素 `target` 的对应索引。
=== "<1>" === "<1>"
![binary_search_step1](binary_search.assets/binary_search_step1.png) ![二分查找步骤](binary_search.assets/binary_search_step1.png)
=== "<2>" === "<2>"
![binary_search_step2](binary_search.assets/binary_search_step2.png) ![binary_search_step2](binary_search.assets/binary_search_step2.png)

@ -11,7 +11,7 @@
完成此次冒泡操作后,**数组最大元素已在正确位置,接下来只需排序剩余 $n - 1$ 个元素**。 完成此次冒泡操作后,**数组最大元素已在正确位置,接下来只需排序剩余 $n - 1$ 个元素**。
=== "<1>" === "<1>"
![bubble_operation_step1](bubble_sort.assets/bubble_operation_step1.png) ![冒泡操作步骤](bubble_sort.assets/bubble_operation_step1.png)
=== "<2>" === "<2>"
![bubble_operation_step2](bubble_sort.assets/bubble_operation_step2.png) ![bubble_operation_step2](bubble_sort.assets/bubble_operation_step2.png)

@ -19,7 +19,7 @@
需要注意,由于从长度为 1 的子数组开始合并,所以 **每个子数组都是有序的**。因此,合并任务本质是要 **将两个有序子数组合并为一个有序数组**。 需要注意,由于从长度为 1 的子数组开始合并,所以 **每个子数组都是有序的**。因此,合并任务本质是要 **将两个有序子数组合并为一个有序数组**。
=== "<1>" === "<1>"
![merge_sort_step1](merge_sort.assets/merge_sort_step1.png) ![归并排序步骤](merge_sort.assets/merge_sort_step1.png)
=== "<2>" === "<2>"
![merge_sort_step2](merge_sort.assets/merge_sort_step2.png) ![merge_sort_step2](merge_sort.assets/merge_sort_step2.png)

@ -11,7 +11,7 @@
「哨兵划分」执行完毕后,原数组被划分成两个部分,即 **左子数组** 和 **右子数组**,且满足 **左子数组任意元素 < 基准数 < 右子数组任意元素**。因此,接下来我们只需要排序两个子数组即可。 「哨兵划分」执行完毕后,原数组被划分成两个部分,即 **左子数组** 和 **右子数组**,且满足 **左子数组任意元素 < 基准数 < 右子数组任意元素**。因此,接下来我们只需要排序两个子数组即可。
=== "<1>" === "<1>"
![pivot_division_step1](quick_sort.assets/pivot_division_step1.png) ![哨兵划分步骤](quick_sort.assets/pivot_division_step1.png)
=== "<2>" === "<2>"
![pivot_division_step2](quick_sort.assets/pivot_division_step2.png) ![pivot_division_step2](quick_sort.assets/pivot_division_step2.png)

@ -298,7 +298,7 @@
我们将双向链表的头结点和尾结点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除结点。 我们将双向链表的头结点和尾结点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除结点。
=== "LinkedListDeque" === "LinkedListDeque"
![linkedlist_deque](deque.assets/linkedlist_deque.png) ![基于链表实现双向队列的入队出队操作](deque.assets/linkedlist_deque.png)
=== "pushLast()" === "pushLast()"
![linkedlist_deque_push_last](deque.assets/linkedlist_deque_push_last.png) ![linkedlist_deque_push_last](deque.assets/linkedlist_deque_push_last.png)
@ -389,7 +389,7 @@
与基于数组实现队列类似,我们也可以使用环形数组来实现双向队列。在实现队列的基础上,增加实现“队首入队”和“队尾出队”方法即可。 与基于数组实现队列类似,我们也可以使用环形数组来实现双向队列。在实现队列的基础上,增加实现“队首入队”和“队尾出队”方法即可。
=== "ArrayDeque" === "ArrayDeque"
![array_deque](deque.assets/array_deque.png) ![基于数组实现双向队列的入队出队操作](deque.assets/array_deque.png)
=== "pushLast()" === "pushLast()"
![array_deque_push_last](deque.assets/array_deque_push_last.png) ![array_deque_push_last](deque.assets/array_deque_push_last.png)

@ -263,7 +263,7 @@
我们将链表的「头结点」和「尾结点」分别看作是队首和队尾,并规定队尾只可添加结点,队首只可删除结点。 我们将链表的「头结点」和「尾结点」分别看作是队首和队尾,并规定队尾只可添加结点,队首只可删除结点。
=== "LinkedListQueue" === "LinkedListQueue"
![linkedlist_queue](queue.assets/linkedlist_queue.png) ![基于链表实现队列的入队出队操作](queue.assets/linkedlist_queue.png)
=== "push()" === "push()"
![linkedlist_queue_push](queue.assets/linkedlist_queue_push.png) ![linkedlist_queue_push](queue.assets/linkedlist_queue_push.png)
@ -347,7 +347,7 @@
观察发现,入队与出队操作都仅需单次操作即可完成,时间复杂度皆为 $O(1)$ 。 观察发现,入队与出队操作都仅需单次操作即可完成,时间复杂度皆为 $O(1)$ 。
=== "ArrayQueue" === "ArrayQueue"
![array_queue](queue.assets/array_queue.png) ![基于数组实现队列的入队出队操作](queue.assets/array_queue.png)
=== "push()" === "push()"
![array_queue_push](queue.assets/array_queue_push.png) ![array_queue_push](queue.assets/array_queue_push.png)

@ -266,7 +266,7 @@
对于入栈操作,将元素插入到链表头部即可,这种结点添加方式被称为“头插法”。而对于出栈操作,则将头结点从链表中删除即可。 对于入栈操作,将元素插入到链表头部即可,这种结点添加方式被称为“头插法”。而对于出栈操作,则将头结点从链表中删除即可。
=== "LinkedListStack" === "LinkedListStack"
![linkedlist_stack](stack.assets/linkedlist_stack.png) ![基于链表实现栈的入栈出栈操作](stack.assets/linkedlist_stack.png)
=== "push()" === "push()"
![linkedlist_stack_push](stack.assets/linkedlist_stack_push.png) ![linkedlist_stack_push](stack.assets/linkedlist_stack_push.png)
@ -341,7 +341,7 @@
使用「数组」实现栈时,考虑将数组的尾部当作栈顶。这样设计下,「入栈」与「出栈」操作就对应在数组尾部「添加元素」与「删除元素」,时间复杂度都为 $O(1)$ 。 使用「数组」实现栈时,考虑将数组的尾部当作栈顶。这样设计下,「入栈」与「出栈」操作就对应在数组尾部「添加元素」与「删除元素」,时间复杂度都为 $O(1)$ 。
=== "ArrayStack" === "ArrayStack"
![array_stack](stack.assets/array_stack.png) ![基于数组实现栈的入栈出栈操作](stack.assets/array_stack.png)
=== "push()" === "push()"
![array_stack_push](stack.assets/array_stack_push.png) ![array_stack_push](stack.assets/array_stack_push.png)

@ -310,7 +310,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作其可 **在不影
如下图所示(结点下方为「平衡因子」),从底至顶看,二叉树中首个失衡结点是 **结点 3**。我们聚焦在以该失衡结点为根结点的子树上,将该结点记为 `node` ,将其左子结点记为 `child` ,执行「右旋」操作。完成右旋后,该子树已经恢复平衡,并且仍然为二叉搜索树。 如下图所示(结点下方为「平衡因子」),从底至顶看,二叉树中首个失衡结点是 **结点 3**。我们聚焦在以该失衡结点为根结点的子树上,将该结点记为 `node` ,将其左子结点记为 `child` ,执行「右旋」操作。完成右旋后,该子树已经恢复平衡,并且仍然为二叉搜索树。
=== "<1>" === "<1>"
![avltree_right_rotate_step1](avl_tree.assets/avltree_right_rotate_step1.png) ![右旋操作步骤](avl_tree.assets/avltree_right_rotate_step1.png)
=== "<2>" === "<2>"
![avltree_right_rotate_step2](avl_tree.assets/avltree_right_rotate_step2.png) ![avltree_right_rotate_step2](avl_tree.assets/avltree_right_rotate_step2.png)

@ -18,7 +18,7 @@
- 若 `cur.val = num` ,说明找到目标结点,跳出循环并返回该结点即可; - 若 `cur.val = num` ,说明找到目标结点,跳出循环并返回该结点即可;
=== "<1>" === "<1>"
![bst_search_step1](binary_search_tree.assets/bst_search_step1.png) ![查找结点步骤](binary_search_tree.assets/bst_search_step1.png)
=== "<2>" === "<2>"
![bst_search_step2](binary_search_tree.assets/bst_search_step2.png) ![bst_search_step2](binary_search_tree.assets/bst_search_step2.png)
@ -185,7 +185,7 @@
3. 使用 `nex` 替换待删除结点; 3. 使用 `nex` 替换待删除结点;
=== "<1>" === "<1>"
![bst_remove_case3_step1](binary_search_tree.assets/bst_remove_case3_step1.png) ![删除结点(度为 2步骤](binary_search_tree.assets/bst_remove_case3_step1.png)
=== "<2>" === "<2>"
![bst_remove_case3_step2](binary_search_tree.assets/bst_remove_case3_step2.png) ![bst_remove_case3_step2](binary_search_tree.assets/bst_remove_case3_step2.png)

Loading…
Cancel
Save