mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-24 04:16:29 +08:00
Update README
This commit is contained in:
parent
550024f69b
commit
faba5af781
19 changed files with 61 additions and 57 deletions
14
README.md
14
README.md
|
@ -1,5 +1,5 @@
|
|||
<p align="center">
|
||||
<a href="https://krahets.github.io/hello-algo/">
|
||||
<a href="https://www.hello-algo.com/">
|
||||
<img src="docs/index.assets/conceptual_rendering.png" width="220">
|
||||
</a>
|
||||
</p>
|
||||
|
@ -12,17 +12,11 @@
|
|||
动画图解、能运行、可讨论的</br>数据结构与算法快速入门教程
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://krahets.github.io/hello-algo/">
|
||||
<img src="docs/index.assets/demo.png" width="700">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<em>
|
||||
前往阅读 -
|
||||
<a href="https://hello-algo.pages.dev/">
|
||||
hello-algo.pages.dev
|
||||
前往阅读 >>
|
||||
<a href="https://www.hello-algo.com/">
|
||||
hello-algo.com
|
||||
</a>
|
||||
</em>
|
||||
</p>
|
||||
|
|
|
@ -8,7 +8,7 @@ comments: true
|
|||
|
||||
![array_definition](array.assets/array_definition.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 数组定义与存储方式 </p>
|
||||
<p align="center"> Fig. 数组定义与存储方式 </p>
|
||||
|
||||
!!! note
|
||||
|
||||
|
@ -42,7 +42,7 @@ comments: true
|
|||
|
||||
![array_memory_location_calculation](array.assets/array_memory_location_calculation.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 数组元素的内存地址计算 </p>
|
||||
<p align="center"> Fig. 数组元素的内存地址计算 </p>
|
||||
|
||||
```java title=""
|
||||
// 元素内存地址 = 数组内存地址 + 元素长度 * 元素索引
|
||||
|
@ -117,7 +117,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex
|
|||
|
||||
![array_insert_remove_element](array.assets/array_insert_remove_element.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 在数组中插入与删除元素 </p>
|
||||
<p align="center"> Fig. 在数组中插入与删除元素 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ comments: true
|
|||
|
||||
![linkedlist_definition](linked_list.assets/linkedlist_definition.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 链表定义与存储方式 </p>
|
||||
<p align="center"> Fig. 链表定义与存储方式 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
|
@ -86,7 +86,7 @@ comments: true
|
|||
|
||||
![linkedlist_insert_remove_node](linked_list.assets/linkedlist_insert_remove_node.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 在链表中插入与删除结点 </p>
|
||||
<p align="center"> Fig. 在链表中插入与删除结点 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
|
@ -219,4 +219,4 @@ comments: true
|
|||
|
||||
![linkedlist_common_types](linked_list.assets/linkedlist_common_types.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 常见链表类型 </p>
|
||||
<p align="center"> Fig. 常见链表类型 </p>
|
||||
|
|
|
@ -11,7 +11,7 @@ comments: true
|
|||
|
||||
## 数组 VS 链表
|
||||
|
||||
<p style="text-align:center"> Table. 数组与链表特点对比 </p>
|
||||
<p align="center"> Table. 数组与链表特点对比 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
@ -28,7 +28,7 @@ comments: true
|
|||
|
||||
「缓存局部性(Cache locality)」涉及到了计算机操作系统,在本书不做展开介绍,建议有兴趣的同学 Google / Baidu 一下。
|
||||
|
||||
<p style="text-align:center"> Table. 数组与链表操作时间复杂度 </p>
|
||||
<p align="center"> Table. 数组与链表操作时间复杂度 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ comments: true
|
|||
|
||||
![space_types](space_complexity.assets/space_types.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 算法使用的相关空间 </p>
|
||||
<p align="center"> Fig. 算法使用的相关空间 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
|
@ -144,7 +144,7 @@ $$
|
|||
|
||||
![space_complexity_common_types](space_complexity.assets/space_complexity_common_types.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 空间复杂度的常见类型 </p>
|
||||
<p align="center"> Fig. 空间复杂度的常见类型 </p>
|
||||
|
||||
!!! tip
|
||||
|
||||
|
@ -252,7 +252,7 @@ $$
|
|||
|
||||
![space_complexity_recursive_linear](space_complexity.assets/space_complexity_recursive_linear.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 递归函数产生的线性阶空间复杂度 </p>
|
||||
<p align="center"> Fig. 递归函数产生的线性阶空间复杂度 </p>
|
||||
|
||||
### 平方阶 $O(n^2)$
|
||||
|
||||
|
@ -317,7 +317,7 @@ $$
|
|||
|
||||
![space_complexity_recursive_quadratic](space_complexity.assets/space_complexity_recursive_quadratic.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 递归函数产生的平方阶空间复杂度 </p>
|
||||
<p align="center"> Fig. 递归函数产生的平方阶空间复杂度 </p>
|
||||
|
||||
### 指数阶 $O(2^n)$
|
||||
|
||||
|
@ -350,7 +350,7 @@ $$
|
|||
|
||||
![space_complexity_exponential](space_complexity.assets/space_complexity_exponential.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 满二叉树下的指数阶空间复杂度 </p>
|
||||
<p align="center"> Fig. 满二叉树下的指数阶空间复杂度 </p>
|
||||
|
||||
### 对数阶 $O(\log n)$
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ $$
|
|||
|
||||
![time_complexity_first_example](time_complexity.assets/time_complexity_first_example.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 算法 A, B, C 的时间增长趋势 </p>
|
||||
<p align="center"> Fig. 算法 A, B, C 的时间增长趋势 </p>
|
||||
|
||||
相比直接统计算法运行时间,时间复杂度分析的做法有什么好处呢?以及有什么不足?
|
||||
|
||||
|
@ -153,7 +153,7 @@ $T(n)$ 是个一次函数,说明时间增长趋势是线性的,因此易得
|
|||
|
||||
![asymptotic_upper_bound](time_complexity.assets/asymptotic_upper_bound.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 函数的渐进上界 </p>
|
||||
<p align="center"> Fig. 函数的渐进上界 </p>
|
||||
|
||||
本质上看,计算渐进上界就是在找一个函数 $f(n)$ ,**使得在 $n$ 趋向于无穷大时,$T(n)$ 和 $f(n)$ 处于相同的增长级别(仅相差一个常数项 $c$ 的倍数)**。
|
||||
|
||||
|
@ -245,7 +245,7 @@ $$
|
|||
|
||||
![time_complexity_common_types](time_complexity.assets/time_complexity_common_types.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 时间复杂度的常见类型 </p>
|
||||
<p align="center"> Fig. 时间复杂度的常见类型 </p>
|
||||
|
||||
!!! tip
|
||||
|
||||
|
@ -375,7 +375,7 @@ $$
|
|||
|
||||
![time_complexity_constant_linear_quadratic](time_complexity.assets/time_complexity_constant_linear_quadratic.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 常数阶、线性阶、平方阶的时间复杂度 </p>
|
||||
<p align="center"> Fig. 常数阶、线性阶、平方阶的时间复杂度 </p>
|
||||
|
||||
以「冒泡排序」为例,外层循环 $n - 1$ 次,内层循环 $n-1, n-2, \cdots, 2, 1$ 次,平均为 $\frac{n}{2}$ 次,因此时间复杂度为 $O(n^2)$ 。
|
||||
|
||||
|
@ -454,7 +454,7 @@ $$
|
|||
|
||||
![time_complexity_exponential](time_complexity.assets/time_complexity_exponential.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 指数阶的时间复杂度 </p>
|
||||
<p align="center"> Fig. 指数阶的时间复杂度 </p>
|
||||
|
||||
在实际算法中,指数阶常出现于递归函数。例如以下代码,不断地一分为二,分裂 $n$ 次后停止。
|
||||
|
||||
|
@ -516,7 +516,7 @@ $$
|
|||
|
||||
![time_complexity_logarithmic](time_complexity.assets/time_complexity_logarithmic.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 对数阶的时间复杂度 </p>
|
||||
<p align="center"> Fig. 对数阶的时间复杂度 </p>
|
||||
|
||||
与指数阶类似,对数阶也常出现于递归函数。以下代码形成了一个高度为 $\log_2 n$ 的递归树。
|
||||
|
||||
|
@ -577,7 +577,7 @@ $$
|
|||
|
||||
![time_complexity_logarithmic_linear](time_complexity.assets/time_complexity_logarithmic_linear.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 线性对数阶的时间复杂度 </p>
|
||||
<p align="center"> Fig. 线性对数阶的时间复杂度 </p>
|
||||
|
||||
### 阶乘阶 $O(n!)$
|
||||
|
||||
|
@ -618,7 +618,7 @@ $$
|
|||
|
||||
![time_complexity_factorial](time_complexity.assets/time_complexity_factorial.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 阶乘阶的时间复杂度 </p>
|
||||
<p align="center"> Fig. 阶乘阶的时间复杂度 </p>
|
||||
|
||||
## 最差、最佳、平均时间复杂度
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ comments: true
|
|||
|
||||
![classification_logic_structure](classification_of_data_strcuture.assets/classification_logic_structure.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 线性与非线性数据结构 </p>
|
||||
<p align="center"> Fig. 线性与非线性数据结构 </p>
|
||||
|
||||
## 物理结构:连续与离散
|
||||
|
||||
|
@ -29,7 +29,7 @@ comments: true
|
|||
|
||||
![classification_phisical_structure](classification_of_data_strcuture.assets/classification_phisical_structure.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 连续空间存储与离散空间存储 </p>
|
||||
<p align="center"> Fig. 连续空间存储与离散空间存储 </p>
|
||||
|
||||
**所有数据结构都是基于数组、或链表、或两者组合实现的。** 例如栈和队列,既可以使用数组实现、也可以使用链表实现,而例如哈希表,其实现同时包含了数组和链表。
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ comments: true
|
|||
|
||||
1 字节 (byte) = 8 比特 (bit) , 1 比特即最基本的 1 个二进制位
|
||||
|
||||
<p style="text-align:center"> Table. Java 的基本数据类型 </p>
|
||||
<p align="center"> Table. Java 的基本数据类型 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
@ -57,7 +57,7 @@ comments: true
|
|||
=== "C++"
|
||||
|
||||
```cpp title=""
|
||||
|
||||
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
@ -76,6 +76,6 @@ comments: true
|
|||
|
||||
![computer_memory_location](data_and_memory.assets/computer_memory_location.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 内存条、内存空间、内存地址 </p>
|
||||
<p align="center"> Fig. 内存条、内存空间、内存地址 </p>
|
||||
|
||||
**内存资源是设计数据结构与算法的重要考虑因素。** 内存是所有程序的公共资源,当内存被某程序占用时,不能被其它程序同时使用。我们需要根据剩余内存资源的情况来设计算法。例如,若剩余内存空间有限,则要求算法占用的峰值内存不能超过系统剩余内存;若运行的程序很多、缺少大块连续的内存空间,则要求选取的数据结构必须能够存储在离散的内存空间内。
|
||||
|
|
|
@ -77,7 +77,7 @@ comments: true
|
|||
|
||||
![relationship_between_data_structure_and_algorithm](index.assets/relationship_between_data_structure_and_algorithm.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 数据结构与算法的关系 </p>
|
||||
<p align="center"> Fig. 数据结构与算法的关系 </p>
|
||||
|
||||
!!! tip "约定俗成的习惯"
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ comments: true
|
|||
|
||||
!!! quote ""
|
||||
|
||||
<p style="text-align:center"> 追风赶月莫停留,平芜尽处是春山 </p>
|
||||
<p style="text-align:center"> 一起加油! </p>
|
||||
<p align="center"> 追风赶月莫停留,平芜尽处是春山 </p>
|
||||
<p align="center"> 一起加油! </p>
|
||||
|
||||
## 内容结构
|
||||
|
||||
|
@ -31,7 +31,7 @@ comments: true
|
|||
|
||||
![mindmap](index.assets/mindmap.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 知识点思维导图 </p>
|
||||
<p align="center"> Fig. 知识点思维导图 </p>
|
||||
|
||||
### 复杂度分析
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- 二分查找利用数据的有序性,通过循环不断缩小一半搜索区间来实现查找,其要求输入数据是有序的,并且仅适用于数组或基于数组实现的数据结构。
|
||||
- 哈希查找借助哈希表来实现常数阶时间复杂度的查找操作,体现以空间换时间的算法思想。
|
||||
|
||||
<p style="text-align:center"> Table. 三种查找方法对比 </p>
|
||||
<p align="center"> Table. 三种查找方法对比 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ comments: true
|
|||
|
||||
![bubble_operation_step7](bubble_sort.assets/bubble_operation_step7.png)
|
||||
|
||||
<p align="center"> Fig. 冒泡操作 </p>
|
||||
|
||||
## 算法流程
|
||||
|
||||
1. 设数组长度为 $n$ ,完成第一轮「冒泡」后,数组最大元素已在正确位置,接下来只需排序剩余 $n - 1$ 个元素。
|
||||
|
@ -52,6 +54,8 @@ comments: true
|
|||
|
||||
![bubble_sort](bubble_sort.assets/bubble_sort.png)
|
||||
|
||||
<p align="center"> Fig. 冒泡排序流程 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
|
|
|
@ -12,6 +12,8 @@ comments: true
|
|||
|
||||
![insertion_operation](insertion_sort.assets/insertion_operation.png)
|
||||
|
||||
<p align="center"> Fig. 插入操作 </p>
|
||||
|
||||
## 算法流程
|
||||
|
||||
1. 第 1 轮先选取数组的 **第 2 个元素** 为 `base` ,执行「插入操作」后, **数组前 2 个元素已完成排序**。
|
||||
|
@ -22,6 +24,8 @@ comments: true
|
|||
|
||||
![insertion_sort](insertion_sort.assets/insertion_sort.png)
|
||||
|
||||
<p align="center"> Fig. 插入排序流程 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
|
|
|
@ -33,7 +33,7 @@ comments: true
|
|||
=== "Step 9"
|
||||
![pivot_division_step9](quick_sort.assets/pivot_division_step9.png)
|
||||
|
||||
哨兵划分实现代码如下。
|
||||
<p align="center"> Fig. 哨兵划分 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
|
@ -75,6 +75,8 @@ comments: true
|
|||
|
||||
![quick_sort](quick_sort.assets/quick_sort.png)
|
||||
|
||||
<p align="center"> Fig. 快速排序流程 </p>
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
![deque_operations](deque.assets/deque_operations.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 双向队列的操作 </p>
|
||||
<p align="center"> Fig. 双向队列的操作 </p>
|
||||
|
||||
## 双向队列常用操作
|
||||
|
||||
双向队列的常用操作见下表,方法名需根据编程语言设定来具体确定。
|
||||
|
||||
<p style="text-align:center"> Table. 双向队列的常用操作 </p>
|
||||
<p align="center"> Table. 双向队列的常用操作 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ comments: true
|
|||
|
||||
![queue_operations](queue.assets/queue_operations.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 队列的先入先出特性 </p>
|
||||
<p align="center"> Fig. 队列的先入先出特性 </p>
|
||||
|
||||
## 队列常用操作
|
||||
|
||||
队列的常用操作见下表,方法命名需根据编程语言的设定来具体确定。
|
||||
|
||||
<p style="text-align:center"> Table. 队列的常用操作 </p>
|
||||
<p align="center"> Table. 队列的常用操作 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ comments: true
|
|||
|
||||
![stack_operations](stack.assets/stack_operations.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 栈的先入后出特性 </p>
|
||||
<p align="center"> Fig. 栈的先入后出特性 </p>
|
||||
|
||||
## 栈常用操作
|
||||
|
||||
栈的常用操作见下表,方法名需根据编程语言设定来具体确定。
|
||||
|
||||
<p style="text-align:center"> Table. 栈的常用操作 </p>
|
||||
<p align="center"> Table. 栈的常用操作 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ comments: true
|
|||
|
||||
![binary_tree_definition](binary_tree.assets/binary_tree_definition.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 子结点与子树 </p>
|
||||
<p align="center"> Fig. 子结点与子树 </p>
|
||||
|
||||
需要注意,父结点、子结点、子树是可以向下递推的。例如,如果将上图的「结点 2」看作父结点,那么其左子节点和右子结点分别为「结点 4」和「结点 5」,左子树和右子树分别为「结点 4 以下的树」和「结点 5 以下的树」。
|
||||
|
||||
|
@ -42,7 +42,7 @@ comments: true
|
|||
|
||||
![binary_tree_terminology](binary_tree.assets/binary_tree_terminology.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 二叉树的常见术语 </p>
|
||||
<p align="center"> Fig. 二叉树的常见术语 </p>
|
||||
|
||||
## 二叉树最佳和最差结构
|
||||
|
||||
|
@ -50,7 +50,7 @@ comments: true
|
|||
|
||||
![binary_tree_corner_cases](binary_tree.assets/binary_tree_corner_cases.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 二叉树的最佳和最差结构 </p>
|
||||
<p align="center"> Fig. 二叉树的最佳和最差结构 </p>
|
||||
|
||||
在最佳和最差结构下,二叉树的结点数量和高度等性质达到最大(最小)值。
|
||||
|
||||
|
@ -88,7 +88,7 @@ comments: true
|
|||
|
||||
![binary_tree_add_remove](binary_tree.assets/binary_tree_add_remove.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 在二叉树中插入与删除结点 </p>
|
||||
<p align="center"> Fig. 在二叉树中插入与删除结点 </p>
|
||||
|
||||
```java title="binary_tree.java"
|
||||
TreeNode P = new TreeNode(0);
|
||||
|
@ -115,7 +115,7 @@ n1.left = n2;
|
|||
|
||||
![binary_tree_bfs](binary_tree.assets/binary_tree_bfs.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 二叉树的层序遍历 </p>
|
||||
<p align="center"> Fig. 二叉树的层序遍历 </p>
|
||||
|
||||
广度优先遍历一般借助「队列」来实现。队列的规则是 “先进先出” ,广度优先遍历的规则是 ”一层层平推“ ,两者背后的思想是一致的。
|
||||
|
||||
|
@ -148,7 +148,7 @@ n1.left = n2;
|
|||
|
||||
![binary_tree_dfs](binary_tree.assets/binary_tree_dfs.png)
|
||||
|
||||
<p style="text-align:center"> Fig. 二叉树的前 / 中 / 后序遍历 </p>
|
||||
<p align="center"> Fig. 二叉树的前 / 中 / 后序遍历 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ hide:
|
|||
|
||||
<h2 style="text-align:center"> 「清晰动画讲解」 </h2>
|
||||
|
||||
<p style="text-align:center"> 借助动画介绍重点,提升知识吸收效率</br>HTML 文档,支持笔记本、平板、手机多种终端 </p>
|
||||
<p align="center"> 借助动画介绍重点,提升知识吸收效率</br>HTML 文档,支持笔记本、平板、手机多种终端 </p>
|
||||
|
||||
![algorithm_animation](index.assets/animation.gif)
|
||||
|
||||
|
@ -29,7 +29,7 @@ hide:
|
|||
|
||||
<h2 style="text-align:center"> 「代码实践导向」 </h2>
|
||||
|
||||
<p style="text-align:center"> 示例代码皆可一键运行,在调试中加深理解</br>提供 Java, C++, Python 源码与详细注释 </p>
|
||||
<p align="center"> 示例代码皆可一键运行,在调试中加深理解</br>提供 Java, C++, Python 源码与详细注释 </p>
|
||||
|
||||
![running_code](index.assets/running_code.gif)
|
||||
|
||||
|
@ -37,7 +37,7 @@ hide:
|
|||
|
||||
<h2 style="text-align:center"> 「可讨论与提问」 </h2>
|
||||
|
||||
<p style="text-align:center"> 在评论区与小伙伴们一起学习进步</br>作者定期回复评论问题(一般 < 72h ) </p>
|
||||
<p align="center"> 在评论区与小伙伴们一起学习进步</br>作者定期回复评论问题(一般 < 72h ) </p>
|
||||
|
||||
![comment](index.assets/comment.gif)
|
||||
|
||||
|
|
Loading…
Reference in a new issue