Skip to content

Commit c81ebc6

Browse files
committed
完成算法分析;准备哈希表
1 parent 4b11b04 commit c81ebc6

File tree

6 files changed

+68
-17
lines changed

6 files changed

+68
-17
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ Python 抽象程度比较高, 我们能用更少的代码来实现功能,同
139139
对于找工作的同学提升面试成功率。
140140

141141

142-
143142
## 工具
144143

145144
推荐使用以下工具进行开发,如果使用编辑器最好装对 应 Python 插件:
@@ -173,5 +172,5 @@ pip install https://github.com/mitya57/python-markdown-math/archive/master.zip
173172
编写并查看:
174173
```sh
175174
mkdocs serve # 修改自动更新,http://localhost:8000 访问
175+
# 数学公式参考 https://www.zybuluo.com/codeep/note/163962
176176
```
177-

docs/6_算法分析/big_o.md

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ https://book.douban.com/subject/10607365/) 中给的一个例子:
1010

1111
考虑计算一个 n * n 矩阵所有元素的和(如果你不知道矩阵,就理解为一个二维数组):
1212

13-
[0, 1, 2]
14-
[3, 4, 5]
15-
[6, 7, 8]
13+
$$
14+
\begin{bmatrix}
15+
0 & 1 & 2 \\
16+
3 & 4 & 5 \\
17+
6 & 7 & 8 \\
18+
\end{bmatrix}
19+
$$
1620

1721
这里列举两种方式:
1822

@@ -34,24 +38,51 @@ for i in range(n):
3438
total_sum = total_sum + row_sum[i] # 注意这里和上边的不同
3539
```
3640

37-
v1 版本的关键操作在 j 循环里,两步加法操作,由于嵌套在第一个循环里,操作步骤是 $(2n) * n = 2n^2$。
38-
v2 版本的 total_sum 只有 n 次操作,它的操作次数是 n + n*n = n^2 + n
41+
v1 版本的关键操作在 j 循环里,两步加法操作,由于嵌套在第一个循环里,操作步骤是 $ (2n) * n = 2n^2 $。
42+
43+
v2 版本的 total_sum 只有 n 次操作,它的操作次数是 $ n + n*n = n^2 + n $。
3944

4045

4146
这里你可能还感觉不到它们有多大差别,因为计算机执行的太快了,但是当 n 增长特别快的时候,总的操作次数差距就很明显了:
4247

43-
n | 2n^2 | n^2 +n |
48+
n | $ 2n^2 $ | $ n^2 +n $ |
4449
-------|----------------|----------------|
4550
10 | 200 | 110 |
4651
100 | 20,000 | 10,100 |
4752
1000 | 2,000,000 | 1,001,000 |
4853
10000 | 200,000,000 | 100,010,000 |
4954
100000 | 20,000,000,000 | 10,000,100,000 |
5055

56+
通常我们不太关注每个算法具体执行了多少次,而更关心随着输入规模 n 的增加,算法运行时间将以什么速度增加。为此计算机科学家定义了一个符号,
57+
用来表示在最糟糕的情况下算法的运行时间,大 O 符号,在数学上称之为渐进上界(《算法导论》)。
58+
59+
# 如何计算时间复杂度
60+
上边我们列举了两个版本的计算矩阵和的代码,你看到了两个公式:
61+
62+
- v1: $ 2n*n = 2n^2 $
63+
- v2: $ n + n*n = n + n^2 $
64+
65+
当 n 非常大的时候,$ n^2 $ 的数值这里将占主导,我们可以忽略 n 的影响
66+
67+
- v1: $ 2n*n = 2n^2 $
68+
- v2: $ n + n*n = n + n^2 \leq 2n^2 $
5169

52-
$$ x^{y^z}=(1+{\rm e}^x)^{-2xy^w} $$
70+
这里我们可以认为两个算法的时间复杂度均为 $ O(n^2) $
5371

54-
# 时间复杂度
72+
# 常用时间复杂度
73+
这里我们列举一些常用的时间复杂度,按照增长速度排序,日常我们的业务代码中最常用的是指数之前的复杂度,指数和阶乘的增长速度非常快,
74+
当输入比较大的时候用在业务代码里是不可接受的。
75+
76+
O | 名称 | 举例 |
77+
----------|--------------|--------------------|
78+
1 | 常量时间 | 一次赋值 |
79+
$\log n$ | 对数时间 | 折半查找 |
80+
$n$ | 线性时间 | 线性查找 |
81+
n$\log n$ | 对数线性时间 | 快速排序 |
82+
$n^2$ | 平方 | 两重循环 |
83+
$n^3$ | 立方 | 三重循环 |
84+
$2^n$ | 指数 | 递归求斐波那契数列 |
85+
$n!$ | 阶乘 | 旅行商问题 |
5586

5687

5788
# 空间复杂度
@@ -62,11 +93,14 @@ $$ x^{y^z}=(1+{\rm e}^x)^{-2xy^w} $$
6293

6394

6495
# 常见复杂度增长趋势图
65-
为了让你有个直观的感觉,我们来看看一些经典的时间复杂度和对应的增长趋势图。
96+
为了让你有个直观的感觉,我们来看看一些经典的时间复杂度和对应的增长趋势图,不同函数在输入规模增长的时候很快就会有巨大的增长差异
97+
98+
![函数增长趋势图](./function_growth.png)
6699

67100

68101
# 时间换空间,空间换时间
69102
有一些时候时间和空间两者不可兼得,我们会牺牲其中之一来换取另一个。
103+
70104
空间换时间:比如典型的就是 python 中的集合(后面会讲到它的实现原理),虽然它比较浪费空间,但是却能用 O(1)
71105
的时间复杂度来判重。
72106

@@ -80,9 +114,9 @@ $$ x^{y^z}=(1+{\rm e}^x)^{-2xy^w} $$
80114
的时间复杂度吗?你会用数学公式证明吗?
81115
- 你能指出时间和空间权衡的例子吗?往往很多高效的数据结构能同时兼顾时间和空间复杂度,但是有时候我们却得做出一定的权衡
82116

117+
83118
# 参考资料
84-
如果你对数学感兴趣,建议你阅读《算法导论》『函数的增长』这一节。
85-
和《Data Structures and Algorithms in Python》第4章。
119+
如果你对数学感兴趣,建议你阅读《算法导论》『函数的增长』这一节 和《Data Structures and Algorithms in Python》第4章。
86120

87121

88122
(本章我用了 [MathJax](https://www.zybuluo.com/codeep/note/163962) 来书写一些简单的数学公式,使用 "$"包含起来的就是数学公式)
143 KB
Loading

docs/7_哈希表/hashtable.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# 哈希表
2+
不知道你有没有好奇过为什么 Python 里的 dict 和 set 查找速度这么快呢,用了什么黑魔法吗?
3+
经常听别人说哈希表,究竟什么是哈希表呢?这一章我们来介绍哈希表,后续章节我们会看到 Python 中的字典和集合是如何实现的。
4+
5+
# 如何在 O(1) 时间内查找
6+
前面我们已经讲到了数组和链表,数组能通过下标 O(1) 访问,但是删除一个中间元素却要移动其他元素,时间 O(n)。
7+
循环双端链表倒是可以在知道一个节点的情况下迅速删除它,但是吧查找又成了 O(n)。
8+
难道就没有一种方法可以快速定位和删除元素吗?似乎想要快速找到一个元素除了知道下标之外别无他法,于是乎聪明的计算机科学家又想到了一种方法。
9+
能不能给每个元素一种『逻辑下标』,然后直接找到它呢,哈希表就是这种实现。它通过一个函数来计算一个元素应该放在数组哪个位置,当然对于一个
10+
特定的元素,哈希函数每次计算的下标必须要一样才可以:
11+
12+
```
13+
hash(element) = index
14+
```
15+

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
## 痛点
99
- 讲 Python 数据结构和算法的资料很少,中文资料更少
10-
- 很多自学 Python 的工程师对基础不够重视,面试也发现很多数据结构和算法不过关,太多人挂在了基础的数据结构和算法上
10+
- 转行的工程师越来越多,竞争压力越来越大,很多自学 Python 的工程师对基础不够重视,面试也发现很多数据结构和算法不过关,很多人挂在了基础的数据结构和算法上。
1111
- 缺少工程应用场景下的讲解,很多讲算法的资料太『教科书化』。本书实现的代码工程上可用
1212

1313
## 作者简介
@@ -173,5 +173,5 @@ pip install https://github.com/mitya57/python-markdown-math/archive/master.zip
173173
编写并查看:
174174
```sh
175175
mkdocs serve # 修改自动更新,http://localhost:8000 访问
176+
# 数学公式参考 https://www.zybuluo.com/codeep/note/163962
176177
```
177-

mkdocs.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ extra_javascript:
44
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML
55

66
markdown_extensions:
7-
- mdx_math
7+
- mdx_math:
8+
enable_dollar_delimiter: True #for use of inline $..$
9+
810
pages:
911
- 课程简介: 'index.md'
10-
- 课程简介之本方法学算法: '0_课程简介之笨方法学算法/why_and_how_to_learn.md'
12+
- 课程简介之笨方法学算法: '0_课程简介之笨方法学算法/why_and_how_to_learn.md'
1113
- 抽象数据类型和面向对象编程: '1_抽象数据类型和面向对象编程/ADT_OOP.md'
1214
- 数组和列表: '2_数组和列表/array_and_list.md'
1315
- 链表: '3_链表/linked_list.md'
1416
- 队列: '4_队列/queue.md'
1517
- : '5_栈/stack.md'
1618
- 算法分析: '6_算法分析/big_o.md'
19+
- 哈希表: '7_哈希表/hashtable.md'

0 commit comments

Comments
 (0)